home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\EDIT.C < prev    next >
C/C++ Source or Header  |  1995-01-09  |  73KB  |  3,478 lines

  1. /*
  2.  * edit.c: This is really a mishmash of function and such that deal with IRCII
  3.  * commands (both normal and keybinding commands) 
  4.  *
  5.  * Written By Michael Sandrof
  6.  *
  7.  * Copyright(c) 1990 
  8.  *
  9.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  10.  */
  11.  
  12. #ifndef lint
  13. static    char    rcsid[] = "@(#)$Id: edit.c,v 1.31 1994/10/17 12:07:24 mrg Exp $";
  14. #endif
  15.  
  16. #include "irc.h"
  17.  
  18. #include <sys/stat.h>
  19.  
  20. #ifdef ESIX
  21. # include <lan/net_types.h>
  22. #endif
  23.  
  24. #include "term.h"
  25. #include "server.h"
  26. #include "edit.h"
  27. #include "crypt.h"
  28. #include "vars.h"
  29. #include "ircaux.h"
  30. #include "lastlog.h"
  31. #include "window.h"
  32. #include "screen.h"
  33. #include "whois.h"
  34. #include "hook.h"
  35. #include "input.h"
  36. #include "ignore.h"
  37. #include "keys.h"
  38. #include "names.h"
  39. #include "alias.h"
  40. #include "history.h"
  41. #include "funny.h"
  42. #include "ctcp.h"
  43. #include "dcc.h"
  44. #include "translat.h"
  45. #include "output.h"
  46. #include "exec.h"
  47. #include "notify.h"
  48. #include "numbers.h"
  49. #include "status.h"
  50.  
  51. /*
  52.  * current_exec_timer - used to make sure we don't remove a timer
  53.  * from within itself.
  54.  */
  55. static    int    current_exec_timer = -1;
  56.  
  57. static    int    save_which;
  58. static    int    save_do_all;
  59.  
  60. static    void    show_timer();
  61. static    int    create_timer_ref();
  62.  
  63. TimerList *PendingTimers = (TimerList *) 0;
  64.  
  65. /* used with input_move_cursor */
  66. #define RIGHT 1
  67. #define LEFT 0
  68.  
  69. /* used with /save */
  70. #define    SFLAG_ALIAS    0x0001
  71. #define    SFLAG_BIND    0x0002
  72. #define    SFLAG_ON    0x0004
  73. #define    SFLAG_SET    0x0008
  74. #define    SFLAG_NOTIFY    0x0010
  75. #define    SFLAG_DIGRAPH    0x0020
  76.  
  77. /* The maximum number of recursive LOAD levels allowed */
  78. #define MAX_LOAD_DEPTH 10
  79.  
  80. /* recv_nick: the nickname of the last person to send you a privmsg */
  81.     char    *recv_nick = NULL;
  82.  
  83. /* sent_nick: the nickname of the last person to whom you sent a privmsg */
  84.     char    *sent_nick = NULL;
  85.     char    *sent_body = NULL;
  86.  
  87. /* Used to keep down the nesting of /LOADs and to determine if we
  88.  * should activate the warning for /ONs if the NOVICE variable is set.
  89.  */
  90.     int    load_depth = 0;
  91.  
  92. /* declared in parse.c */
  93. extern    int    doing_privmsg;
  94.  
  95. /* Used to prevent global messaging */
  96. extern    int    in_on_who;
  97.  
  98. typedef    struct    WaitCmdstru
  99. {
  100.     char    *stuff;
  101.     struct    WaitCmdstru    *next;
  102. }    WaitCmd;
  103.  
  104. static    WaitCmd    *start_wait_list = NULL,
  105.         *end_wait_list = NULL;
  106.  
  107.     char    lame_wait_nick[] = "1#LAME";
  108.  
  109. /* a few advance declarations */
  110. static    void    sendlinecmd();
  111. extern    void    ifcmd();
  112. extern    void    do_send_text();
  113. static    void    funny_stuff();
  114. static    void    cd();
  115. extern    void    edit_char();
  116. extern    void    foreach();
  117. extern    void    foreach_handler();
  118. extern    void    fec();
  119. extern    void    whilecmd();
  120.         void    e_quit();
  121. static    void    e_wall();
  122. static    void    send_2comm();
  123. static    void    send_comm();
  124. static    void    send_topic();
  125. static    void    send_kick();
  126. static    void    send_channel_com();
  127. static    void    clear();
  128. static    void    quote();
  129. static    void    e_privmsg();
  130. static    void    flush();
  131. extern    void    server();
  132. static    void    away();
  133. extern    void    query();
  134. static    void    oper();
  135. static    void    e_channel();
  136. extern    void    execcmd();
  137. extern    void    ignore();
  138. static    void    who();
  139. static    void    whois();
  140. static    void    ison();
  141. static    void    userhost();
  142. static    void    info();
  143. static    void    e_nick();
  144. static    void    comment();
  145. extern    void    bindcmd();
  146. extern    void    parsekeycmd();
  147. static    void    sleepcmd();
  148. extern    void    history();
  149. static    void    version();
  150. extern    void    on();
  151. static    void    ctcp();
  152. static    void    dcc();
  153. static    void    deop();
  154. extern    void    echo();
  155. static    void    save_settings();
  156. static    void    redirect();
  157. extern    void    type();
  158. extern    void    notify();
  159. extern    void    waitcmd();
  160. extern    void    parse_line();
  161. static    void    describe();
  162. static    void    me();
  163. static    void    mload();
  164. static    void    mlist();
  165. static    void    evalcmd();
  166. extern    void    direct_expr();
  167. static    void    hook(); static    void    timercmd();
  168. static    void    inputcmd();
  169. static    void    pingcmd();
  170. static    void    xtypecmd();
  171. static    void    beepcmd();
  172. extern    void    stackcmd();
  173. extern    void    queuecmd();
  174. static    void    abortcmd();
  175.  
  176. #ifdef ALLOC_DEBUG
  177. extern    void    alloc_cmd();
  178. #endif
  179.  
  180. /* IrcCommand: structure for each command in the command table */
  181. typedef    struct
  182. {
  183.     char    FAR *name;        /* what the user types */
  184.     char    *server_func;        /* what gets sent to the server
  185.                      * (if anything) */
  186.     void    (*func) ();        /* function that is the command */
  187.     unsigned    flags;
  188. }    IrcCommand;
  189.  
  190. #define NONOVICEABBREV 0x0001
  191. #define    NOINTERACTIVE  0x0002
  192. #define    NOSIMPLESCRIPT 0x0004
  193. #define    NOCOMPLEXSCRIPT 0x0008
  194.  
  195. /*
  196.  * irc_command: all the availble irc commands:  Note that the first entry has
  197.  * a zero length string name and a null server command... this little trick
  198.  * makes "/ blah blah blah" to always be sent to a channel, bypassing queries,
  199.  * etc.  Neato.  This list MUST be sorted.
  200.  */
  201. static    IrcCommand FAR irc_command[] =
  202. {
  203.     { "",        empty_string,    do_send_text,        NOSIMPLESCRIPT| NOCOMPLEXSCRIPT },
  204.     /*
  205.      * I really want to remove #, but it will break a lot of scripts.  - mycroft
  206.      *
  207.      * I agree - it should be converted to a special character in parse_line.
  208.      *                                                            - Troy
  209.      */
  210.     { "#",        NULL,        comment,         0 },
  211.     { ":",        NULL,        comment,         0 },
  212.         { "ABORT",      NULL,           abortcmd,               0 },
  213.     { "ADMIN",    "ADMIN",    send_comm,         0 },
  214.     { "ALIAS",    "0",        alias,            0 },
  215. #ifdef ALLOC_DEBUG
  216.     { "ALLOC",    NULL,        alloc_cmd,        0 },
  217. #endif
  218.     { "ASSIGN",    "1",        alias,            0 },
  219.     { "AWAY",    "AWAY",        away,            0 },
  220.     { "BEEP",    0,        beepcmd,        0 },
  221.     { "BIND",    NULL,        bindcmd,        0 },
  222.     { "BYE",    "QUIT",        e_quit,            NONOVICEABBREV},
  223.     { "CD",        NULL,        cd,            0 },
  224.     { "CHANNEL",    "JOIN",        e_channel,        0 },
  225.     { "CLEAR",    NULL,        clear,            0 },
  226.     { "COMMENT",    NULL,        comment,        0 },
  227.     { "CONNECT",    "CONNECT",    send_comm,        0 },
  228.     { "CTCC",    NULL,        dcc,            0 },
  229.     { "CTCP",    NULL,        ctcp,            0 },
  230.     { "DATE",    "TIME",        send_comm,        0 },
  231.     { "DCC",    NULL,        dcc,            0 },
  232.     { "DEOP",    NULL,        deop,            0 },
  233.     { "DESCRIBE",    NULL,        describe,        0 },
  234.     { "DIE",    "DIE",        send_comm,        0 },
  235.     { "DIGRAPH",    NULL,        digraph,        0 },
  236.     { "ECHO",    NULL,        echo,            0 },
  237.     { "ENCRYPT",    NULL,        encrypt_cmd,        0 },
  238.     { "EVAL",    NULL,        evalcmd,        0 },
  239.     { "EXEC",    NULL,        execcmd,        0 },
  240.     { "EXIT",    "QUIT",        e_quit,            NONOVICEABBREV},
  241.     { "FE",        NULL,        foreach_handler,    0 },
  242.     { "FEC",    NULL,        fec,            0 },
  243.     { "FLUSH",    NULL,        flush,            0 },
  244.     { "FOR",    NULL,        foreach_handler,    0 },
  245.     { "FOREACH",    NULL,        foreach_handler,    0 },
  246.     { "HASH",    "HASH",        send_comm,        0 },
  247.     { "HELP",    NULL,        help,            0 },
  248.     { "HISTORY",    NULL,        history,        0 },
  249.     { "HOOK",    NULL,        hook,            0 },
  250.     { "HOST",    "USERHOST",    userhost,        0 },
  251.     { "IF",        NULL,        ifcmd,            0 },
  252.     { "IGNORE",    NULL,        ignore,            0 },
  253.     { "INFO",    "INFO",        info,            0 },
  254.     { "INPUT",    NULL,        inputcmd,        0 },
  255.     { "INVITE",    "INVITE",    send_comm,        0 },
  256.     { "ISON",    "ISON",        ison,            0 },
  257.     { "JOIN",    "JOIN",        e_channel,        0 },
  258.     { "KICK",    "KICK",        send_kick,        0 },
  259.     { "KILL",    "KILL",        send_2comm,        0 },
  260.     { "LASTLOG",    NULL,        lastlog,        0 },
  261.     { "LEAVE",    "PART",        send_channel_com,    0 },
  262.     { "LINKS",    "LINKS",    send_comm,        NONOVICEABBREV},
  263.     { "LIST",    "LIST",        funny_stuff,        0 },
  264.     { "LOAD",    "LOAD",        load,            0 },
  265.     { "LUSERS",    "LUSERS",    send_comm,        0 },
  266.     { "ME",        NULL,        me,            0 },
  267.     { "MLIST",    NULL,        mlist,            0 },
  268.     { "MLOAD",    NULL,        mload,            0 },
  269.     { "MODE",    "MODE",        send_channel_com,    0 },
  270.     { "MOTD",    "MOTD",        send_comm,        0 },
  271.     { "MSG",    "PRIVMSG",    e_privmsg,        0 },
  272.     { "NAMES",    "NAMES",    funny_stuff,        0 },
  273.     { "NICK",    "NICK",        e_nick,            0 },
  274.     { "NOTE",    "NOTE",        send_comm,        0 },
  275.     { "NOTICE",    "NOTICE",    e_privmsg,        0 },
  276.     { "NOTIFY",    NULL,        notify,            0 },
  277.     { "ON",        NULL,        on,            0 },
  278.     { "OPER",    "OPER",        oper,            0 },
  279.     { "PARSEKEY",    NULL,        parsekeycmd,        0 },
  280.     { "PART",    "PART",        send_channel_com,    0 },
  281.     { "PING",    NULL,         pingcmd,        0 },
  282.     { "QUERY",    NULL,        query,            0 },
  283.     { "QUEUE",      NULL,           queuecmd,               0 },
  284.     { "QUIT",    "QUIT",        e_quit,            NONOVICEABBREV},
  285.     { "QUOTE",    NULL,        quote,            0 },
  286.     { "RBIND",    0,        rbindcmd,        0 },
  287.     { "REDIRECT",    NULL,        redirect,        0 },
  288.     { "REHASH",    "REHASH",    send_comm,        0 },
  289.     { "REQUEST",    NULL,        ctcp,            0 },
  290.     { "RESTART",    "RESTART",    send_comm,        0 },
  291.     { "SAVE",    NULL,        save_settings,        0 },
  292.     { "SAY",    empty_string,    do_send_text,        0 },
  293.     { "SEND",    NULL,        do_send_text,        0 },
  294.     { "SENDLINE",    empty_string,    sendlinecmd,        0 },
  295.     { "SERVER",    NULL,        server,            0 },
  296.     { "SET",    NULL,        set_variable,        0 },
  297.     { "SIGNOFF",    "QUIT",        e_quit,            NONOVICEABBREV},
  298.     { "SLEEP",    NULL,        sleepcmd,        0 },
  299.     { "SQUIT",    "SQUIT",    send_2comm,        0 },
  300.     { "STACK",    NULL,        stackcmd,        0 },
  301.     { "STATS",    "STATS",    send_comm,        0 },
  302.     { "SUMMON",    "SUMMON",    send_comm,        0 },
  303.     { "TIME",    "TIME",        send_comm,        0 },
  304.     { "TIMER",    "TIMER",    timercmd,        0 },
  305.     { "TOPIC",    "TOPIC",    send_topic,        0 },
  306.     { "TRACE",    "TRACE",    send_comm,        0 },
  307.     { "TYPE",    NULL,        type,            0 },
  308.     { "USERHOST",    NULL,        userhost,        0 },
  309.     { "USERS",    "USERS",    send_comm,        0 },
  310.     { "VERSION",    "VERSION",    version,        0 },
  311.     { "VOICE",    "VOICE",    e_privmsg,        0 },
  312.     { "WAIT",    NULL,        waitcmd,        0 },
  313.     { "WALL",    "WALL",        e_wall,            0 },
  314.     { "WALLOPS",    "WALLOPS",    e_wall,            0 },
  315.     { "WHICH",    "WHICH",    load,            0 },
  316.     { "WHILE",    NULL,        whilecmd,        0 },
  317.     { "WHO",    "WHO",        who,            0 },
  318.     { "WHOIS",    "WHOIS",    whois,            0 },
  319.     { "WHOWAS",    "WHOWAS",    whois,            0 },
  320.     { "WINDOW",    NULL,        window,            0 },
  321.     { "XECHO",    "XECHO",    echo,            0 },
  322.     { "XTRA",    "XTRA",        e_privmsg,        0 },
  323.     { "XTYPE",    NULL,        xtypecmd,        0 },
  324.     { NULL,        NULL,        NULL,            0 }
  325. };
  326.  
  327. /* number of entries in irc_command array */
  328. # define    NUMBER_OF_COMMANDS (sizeof(irc_command) / sizeof(IrcCommand)) - 2
  329.  
  330. /*
  331.  * find_command: looks for the given name in the command list, returning a
  332.  * pointer to the first match and the number of matches in cnt.  If no
  333.  * matches are found, null is returned (as well as cnt being 0). The command
  334.  * list is sorted, so we do a binary search.  The returned commands always
  335.  * points to the first match in the list.  If the match is exact, it is
  336.  * returned and cnt is set to the number of matches * -1.  Thus is 4 commands
  337.  * matched, but the first was as exact match, cnt is -4.
  338.  */
  339. static    IrcCommand *
  340. find_command(com, cnt)
  341.     char    *com;
  342.     int    *cnt;
  343. {
  344.     int    len;
  345.  
  346.     if (com && (len = strlen(com)))
  347.     {
  348.         int    min,
  349.         max,
  350.         pos,
  351.         old_pos = -1,
  352.         c;
  353.  
  354.         min = 1;
  355.         max = NUMBER_OF_COMMANDS + 1;
  356.         while (1)
  357.         {
  358.             pos = (max + min) / 2;
  359.             if (pos == old_pos)
  360.             {
  361.                 *cnt = 0;
  362.                 return ((IrcCommand *) 0);
  363.             }
  364.             old_pos = pos;
  365.             c = strncmp(com, irc_command[pos].name, len);
  366.             if (c == 0)
  367.                 break;
  368.             else if (c > 0)
  369.                 min = pos;
  370.             else
  371.                 max = pos;
  372.         }
  373.         *cnt = 0;
  374.         (*cnt)++;
  375.         min = pos - 1;
  376.         while ((min > 0) && (strncmp(com, irc_command[min].name,
  377.                 len) == 0))
  378.         {
  379.             (*cnt)++;
  380.             min--;
  381.         }
  382.         min++;
  383.         max = pos + 1;
  384.         while ((max < NUMBER_OF_COMMANDS + 1) && (strncmp(com,
  385.                 irc_command[max].name, len) == 0))
  386.         {
  387.             (*cnt)++;
  388.             max++;
  389.         }
  390.         if (*cnt)
  391.         {
  392.             if (strlen(irc_command[min].name) == len)
  393.                 *cnt *= -1;
  394.             else if (*cnt == 1 && 
  395.                     irc_command[min].flags&NONOVICEABBREV &&
  396.                     get_int_var(NOVICE_VAR))
  397.             {
  398.                 say("As a novice you may not abbreviate the %s command", irc_command[min].name);
  399.                 *cnt=0;
  400.                 return ((IrcCommand *) 0);
  401.             }
  402.             return (&(irc_command[min]));
  403.         }
  404.         else
  405.             return ((IrcCommand *) 0);
  406.     }
  407.     else
  408.     {
  409.         *cnt = -1;
  410.         return (irc_command);
  411.     }
  412. }
  413.  
  414. /*ARGSUSED*/
  415. static    void
  416. ctcp(command, args)
  417.     char    *command,
  418.         *args;
  419. {
  420.     char    *to,
  421.         *tag;
  422.     int    type;
  423.  
  424.     if ((to = next_arg(args, &args)) != NULL)
  425.     {
  426.         if (!strcmp(to, "*"))
  427.             if ((to = get_channel_by_refnum(0)) == NULL)
  428.                 to = "0";
  429.         if ((tag = next_arg(args, &args)) != NULL)
  430.             upper(tag);
  431.         else
  432.             tag = "VERSION";
  433.         if ((type = in_ctcp()) == -1)
  434.             echo(NULL, "*** You may not use the CTCP command in an ON CTCP_REPLY!");
  435.         else
  436.         {
  437.             if (args && *args)
  438.                 send_ctcp(ctcp_type[type], to, tag, "%s", args);
  439.             else
  440.                 send_ctcp(ctcp_type[type], to, tag, NULL);
  441.         }
  442.     }
  443.     else
  444.         say("Request from whom?");
  445. }
  446.  
  447. /*ARGSUSED*/
  448. static    void
  449. hook(command, args)
  450.     char    *command,
  451.         *args;
  452. {
  453.     if (*args)
  454.         do_hook(HOOK_LIST, "%s", args);
  455.     else
  456.         say("Must supply an argument to HOOK");
  457. }
  458.  
  459. /*ARGSUSED*/
  460. static    void
  461. dcc(command, args)
  462.     char    *command,
  463.         *args;
  464. {
  465.     if (*args)
  466.         process_dcc(args);
  467.     else
  468.         dcc_list((char *) NULL);
  469. }
  470.  
  471. /*ARGSUSED*/
  472. static    void
  473. deop(command, args)
  474.     char    *command,
  475.         *args;
  476. {
  477.     send_to_server("MODE %s -o", get_server_nickname(from_server));
  478. }
  479.  
  480. static    void
  481. funny_stuff(command, args)
  482.     char    *command,
  483.         *args;
  484. {
  485.     char    *arg,
  486.         *stuff;
  487.     int    min = 0,
  488.         max = 0,
  489.         flags = 0,
  490.         len;
  491.  
  492.     stuff = empty_string;
  493.     while ((arg = next_arg(args, &args)) != NULL)
  494.     {
  495.         len = strlen(arg);
  496.         if (my_strnicmp(arg, "-MAX", len) == 0)
  497.         {
  498.             if ((arg = next_arg(args, &args)) != NULL)
  499.                 max = atoi(arg);
  500.         }
  501.         else if (my_strnicmp(arg, "-MIN", len) == 0)
  502.         {
  503.             if ((arg = next_arg(args, &args)) != NULL)
  504.                 min = atoi(arg);
  505.         }
  506.         else if (my_strnicmp(arg, "-ALL", len) == 0)
  507.         {
  508.             flags &= ~(FUNNY_PUBLIC | FUNNY_PRIVATE);
  509.         }
  510.         else if (my_strnicmp(arg, "-PUBLIC", len) == 0)
  511.         {
  512.             flags |= FUNNY_PUBLIC;
  513.             flags &= ~FUNNY_PRIVATE;
  514.         }
  515.         else if (my_strnicmp(arg, "-PRIVATE", len) == 0)
  516.         {
  517.             flags |= FUNNY_PRIVATE;
  518.             flags &= ~FUNNY_PUBLIC;
  519.         }
  520.         else if (my_strnicmp(arg, "-TOPIC", len) == 0)
  521.             flags |= FUNNY_TOPIC;
  522.         else if (my_strnicmp(arg, "-WIDE", len) == 0)
  523.             flags |= FUNNY_WIDE;
  524.         else if (my_strnicmp(arg, "-USERS", len) == 0)
  525.             flags |= FUNNY_USERS;
  526.         else if (my_strnicmp(arg, "-NAME", len) == 0)
  527.             flags |= FUNNY_NAME;
  528.         else
  529.             stuff = arg;
  530.     }
  531.     set_funny_flags(min, max, flags);
  532.     if (strcmp(stuff, "*") == 0)
  533.         if (!(stuff = get_channel_by_refnum(0)))
  534.             stuff = empty_string;
  535.     if (index(stuff, '*'))
  536.     {
  537.         funny_match(stuff);
  538.         send_to_server("%s %s", command, empty_string);
  539.     }
  540.     else
  541.     {
  542.         funny_match(NULL);
  543.         send_to_server("%s %s", command, stuff);
  544.     }
  545. }
  546.  
  547. /*ARGSUSED*/
  548. void
  549. waitcmd(command, args)
  550.     char    *command,
  551.         *args;
  552. {
  553. #ifdef _Windows
  554.     yell("WAIT is not available under Windows");
  555. #else /* Windows */
  556.     int    index;
  557.     char    *flag;
  558.     char    *procindex;
  559.     int    cmd = 0,
  560.         len;
  561.  
  562.     while (args && *args == '-')
  563.     {
  564.         flag = next_arg(args, &args);
  565.         len = strlen(++flag);
  566.         if (!my_strnicmp("CMD", flag, len))
  567.         {
  568.             cmd = 1;
  569.             break;
  570.         }
  571.         else
  572.             yell("Unknown argument to WAIT: %s", flag);
  573.     }
  574.     if ((procindex = next_arg(args, &args)) && *procindex == '%' &&
  575.             (index = get_process_index(&procindex)) != -1)
  576.     {
  577.         if (is_process_running(index))
  578.         {
  579.             if (cmd)
  580.             {
  581.                 add_process_wait(index, args?args:empty_string);
  582.                 return;
  583.             }
  584.             else
  585.                 set_wait_process(index);
  586.         }
  587.         else
  588.         {
  589.             say("Not a valid process!");
  590.             return;
  591.         }
  592.     }
  593.     else if (cmd)
  594.     {
  595.         WaitCmd    *new;
  596.  
  597.         sprintf(buffer, "%s %s", procindex, args);
  598.         new = (WaitCmd *) new_malloc(sizeof(WaitCmd));
  599.         new->stuff = NULL;
  600.         malloc_strcpy(&new->stuff, buffer);
  601.         new->next = NULL;
  602.         if (end_wait_list)
  603.             end_wait_list->next = new;
  604.         end_wait_list = new;
  605.         if (!start_wait_list)
  606.             start_wait_list = new;
  607.         send_to_server("%s", wait_nick);
  608.         return;
  609.     }
  610.     else
  611.         send_to_server("%s", lame_wait_nick);
  612.     if (waiting)
  613.         yell("WAIT has been called recursively.");
  614.  
  615.     waiting = 1;
  616.     irc_io(NULL, NULL, 0, 1);
  617.     waiting = 0;
  618. #endif /* _Windows */
  619. }
  620.  
  621. int
  622. check_wait_command(nick)
  623.     char     *nick;
  624. {
  625.     if (waiting && !strcmp(nick, lame_wait_nick))
  626.     {
  627.         irc_io_loop = 0;
  628.         return 1;
  629.     }
  630.     if (start_wait_list && !strcmp(nick, wait_nick))
  631.     {
  632.         if (start_wait_list->stuff)
  633.         {
  634.             parse_command(start_wait_list->stuff, 0, empty_string);
  635.             new_free(&start_wait_list->stuff);
  636.         }
  637.         start_wait_list = start_wait_list->next;
  638.         return 1;
  639.     }
  640.     return 0;
  641. }
  642.  
  643. /*ARGSUSED*/
  644. static    void
  645. redirect(command, args)
  646.     char    *command,
  647.         *args;
  648. {
  649.     char    *who;
  650.  
  651.     if ((who = next_arg(args, &args)) != NULL)
  652.     {
  653.         if (!strcmp(who, "*"))
  654.             if (!(who = get_channel_by_refnum(0)))
  655.             {
  656.                 say("Must be on a channel to redirect to '*'");
  657.                 return;
  658.             }
  659.         if (!my_stricmp(who, get_server_nickname(from_server)))
  660.         {
  661.             say("You may not redirect output to yourself");
  662.             return;
  663.         }
  664.         window_redirect(who, from_server);
  665.         server_list[from_server].sent = 0;
  666.         parse_line((char *) 0, args, (char *) 0, 0, 0);
  667.         if (server_list[from_server].sent)
  668.             send_to_server("%s", current_screen->redirect_token,
  669.                 current_screen->screennum);
  670.         else
  671.             window_redirect(NULL, from_server);
  672.     }
  673.     else
  674.         say("Usage: REDIRECT <nick|channel|%process> <cmd>");
  675. }
  676.  
  677. /*ARGSUSED*/
  678. static    void
  679. sleepcmd(command, args)
  680.     char    *command,
  681.         *args;
  682. {
  683. #ifndef _Windows
  684.     char    *arg;
  685.  
  686.     if ((arg = next_arg(args, &args)) != NULL)
  687.         sleep(atoi(arg));
  688.     else
  689.         say("SLEEP: you must specify the amount of time to sleep (in seconds)");
  690. #else
  691.     say("SLEEP: Not available under Windows");
  692. #endif
  693. }
  694.  
  695. /*
  696.  * echo: simply displays the args to the screen, or, if it's XECHO,
  697.  * processes the flags first, then displays the text on
  698.  * the screen
  699.  */
  700. void
  701. echo(command, args)
  702.     char    *command,
  703.         *args;
  704. {
  705.     unsigned int    display;
  706.     int    lastlog_level = 0;
  707.     int    from_level = 0;
  708.     char    *flag_arg;
  709.     int    temp;
  710.     Window *old_to_window;
  711.  
  712.     old_to_window = to_window;
  713.     if (command && *command == 'X')
  714.     {
  715.         while (args && *args == '-')
  716.         {
  717.             flag_arg = next_arg(args, &args);
  718.             switch(toupper(flag_arg[1]))
  719.             {
  720.             case 'L':
  721.                 if (!(flag_arg = next_arg(args, &args)))
  722.                     break;
  723.                 if ((temp = parse_lastlog_level(flag_arg)) != 0)
  724.                 {
  725.                     lastlog_level =
  726.                         set_lastlog_msg_level(temp);
  727.                     from_level = message_from_level(temp);
  728.                 }
  729.                 break;
  730.             case 'W':
  731.                 if (!(flag_arg = next_arg(args, &args)))
  732.                     break;
  733.                 if (isdigit(*flag_arg))
  734.                     to_window =
  735.                        get_window_by_refnum(atoi(flag_arg));
  736.                 else
  737.                     to_window =
  738.                         get_window_by_name(flag_arg);
  739.                 break;
  740.             }
  741.             if (!args)
  742.                 args = empty_string;
  743.         }
  744.     }
  745.     display = window_display;
  746.     window_display = 1;
  747.     put_it("%s", args);
  748.     window_display = display;
  749.     if (lastlog_level)
  750.     {
  751.         set_lastlog_msg_level(lastlog_level);
  752.         message_from_level(from_level);
  753.     }
  754.     to_window = old_to_window;
  755. }
  756.  
  757. /*
  758.  */
  759. static    void
  760. oper_password_received(data, line)
  761.     char    *data;
  762.     char    *line;
  763. {
  764.     send_to_server("OPER %s %s", data, line);
  765. }
  766.  
  767. /* oper: the OPER command.  */
  768. /*ARGSUSED*/
  769. static    void
  770. oper(command, args)
  771.     char    *command,
  772.         *args;
  773. {
  774.     char    *password;
  775.     char    *nick;
  776.  
  777.     oper_command = 1;
  778.     if (!(nick = next_arg(args, &args)))
  779.         nick = nickname;
  780.     if (!(password = next_arg(args, &args)))
  781.     {
  782.         add_wait_prompt("Operator Password:",
  783.             oper_password_received, nick, WAIT_PROMPT_LINE);
  784.         return;
  785.     }
  786.     send_to_server("OPER %s %s", nick, password);
  787. }
  788.  
  789. static void really_save();
  790.  
  791. /* Full scale abort.  Does a "save" into the filename in line, and
  792.         then does a coredump */
  793. static  void    abortcmd(line)
  794. char    *line;
  795. {
  796.         char    *filename = next_arg(line, &line);
  797.  
  798.         filename = filename?filename:"irc.aborted";
  799.     save_which = SFLAG_ALIAS | SFLAG_BIND | SFLAG_ON | SFLAG_SET |
  800.                  SFLAG_NOTIFY | SFLAG_DIGRAPH;
  801.         really_save(filename, "y");
  802. #ifdef ALLOC_DEBUG
  803.         alloc_cmd("ALLOC","d");
  804. #endif
  805.         abort();
  806. }
  807.         
  808. /* This generates a file of your ircII setup */
  809. static    void
  810. really_save(ircrc_file, line)
  811.     char    *ircrc_file;
  812.     char    *line;
  813. {
  814.     FILE    *fp;
  815.     int    save_do_all = 0;
  816.  
  817.     if (*line != 'y' && *line != 'Y')
  818.         return;
  819.     if ((fp = fopen(ircrc_file, "w")) != NULL)
  820.     {
  821.         if (save_which & SFLAG_BIND)
  822.             save_bindings(fp, save_do_all);
  823.         if (save_which & SFLAG_ON)
  824.             save_hooks(fp, save_do_all);
  825.         if (save_which & SFLAG_NOTIFY)
  826.             save_notify(fp);
  827.         if (save_which & SFLAG_SET)
  828.             save_variables(fp, save_do_all);
  829.         if (save_which & SFLAG_ALIAS)
  830.             save_aliases(fp, save_do_all);
  831.         if (save_which & SFLAG_DIGRAPH)
  832.             save_digraphs(fp);
  833.         fclose(fp);
  834.         say("IRCII settings saved to %s", ircrc_file);
  835.     }
  836.     else
  837.         say("Error opening %s: %s", ircrc_file, strerror(errno));
  838. }
  839.  
  840. /* save_settings: saves the current state of IRCII to a file */
  841. /*ARGSUSED*/
  842. static    void
  843. save_settings(command, args)
  844.     char    *command,
  845.         *args;
  846. {
  847.     char    *arg;
  848.     int    all = 1;
  849.  
  850.     save_which = save_do_all = 0;
  851.     while ((arg = next_arg(args, &args)) != NULL)
  852.     {
  853.         if ('-' == *arg)
  854.         {
  855.             all = 0;
  856.             arg++;
  857.             if (0 == my_strnicmp("ALIAS", arg, 5))
  858.                 save_which |= SFLAG_ALIAS;
  859.             else if (0 == my_strnicmp("ASSIGN", arg, 6))
  860.                 save_which |= SFLAG_ALIAS;
  861.             else if (0 == my_strnicmp("BIND", arg, 4))
  862.                 save_which |= SFLAG_BIND;
  863.             else if (0 == my_strnicmp("ON", arg, 2))
  864.                 save_which |= SFLAG_ON;
  865.             else if (0 == my_strnicmp("SET", arg, 3))
  866.                 save_which |= SFLAG_SET;
  867.             else if (0 == my_strnicmp("NOTIFY", arg, 6))
  868.                 save_which |= SFLAG_NOTIFY;
  869.             else if (0 == my_strnicmp("DIGRAPH", arg, 7))
  870.                 save_which |= SFLAG_DIGRAPH;
  871.             else if (0 == my_strnicmp("ALL", arg, 7))
  872.                 save_do_all = 1;
  873.             else
  874.             {
  875.                 say("%s: unknown argument", arg);
  876.                 return;
  877.             }
  878.             continue;
  879.         }
  880. #ifdef DAEMON_UID
  881.         if (getuid() == DAEMON_UID)
  882.         {
  883.             say("You may only use the default value");
  884.             return;
  885.         }
  886. #endif /* DAEMON_UID */
  887.         if (!(ircrc_file = expand_twiddle(arg)))
  888.         {
  889.             say("Unknown user");
  890.             return;
  891.         }
  892.     }
  893.     if (all)
  894.         save_which = SFLAG_ALIAS | SFLAG_BIND | SFLAG_ON | SFLAG_SET |
  895.                  SFLAG_NOTIFY | SFLAG_DIGRAPH;
  896.     if (dumb)
  897.         really_save(ircrc_file, "y"); /* REAL dumb!  -lynx */
  898.     else
  899.     {
  900.         sprintf(buffer, "Really write %s? ", ircrc_file);
  901.         add_wait_prompt(buffer, really_save, ircrc_file,
  902.                 WAIT_PROMPT_LINE);
  903.     }
  904. }
  905.  
  906. /*
  907.  * e_channel: does the channel command.  I just added displaying your current
  908.  * channel if none is given 
  909.  */
  910. static    void
  911. e_channel(command, args)
  912.     char    *command,
  913.         *args;
  914. {
  915.     char    *chan;
  916.     char    *old;
  917.     int    len;
  918.  
  919.     if (get_server_version(from_server) > Server2_5)
  920.         command = "JOIN";
  921.     else
  922.         command = "CHANNEL";
  923.     message_from(NULL, LOG_CURRENT);
  924.     if ((chan = next_arg(args, &args)) != NULL)
  925.     {
  926.         if (get_int_var(NOVICE_VAR))
  927.         {
  928.             if ((old = get_channel_by_refnum(0)) && strcmp(old, "0"))
  929.                 send_to_server("PART %s", old);
  930.         }
  931.         len = strlen(chan);
  932.         if (my_strnicmp(chan, "-invite", len) == 0)
  933.         {
  934.             if (invite_channel)
  935.                 send_to_server("%s %s",command, invite_channel);
  936.             else
  937.                 say("You have not been invited to a channel!");
  938.         }
  939.         else
  940.         {
  941.             if (is_on_channel(chan, get_server_nickname(from_server)))
  942.             {
  943.                 is_current_channel(chan, 1);
  944.                 say("You are now talking to channel %s",
  945.                     set_channel_by_refnum(0, chan));
  946.                 update_all_windows();
  947.             }
  948.             else
  949.             {
  950.                 send_to_server("%s %s %s", command, chan, args);
  951.                 malloc_strcpy(&curr_scr_win->waiting_channel,
  952.                     chan);
  953.             }
  954.         }
  955.     }
  956.     else
  957.         list_channels();
  958.     message_from(NULL, LOG_CRAP);
  959. }
  960.  
  961. /* comment: does the /COMMENT command, useful in .ircrc */
  962. /*ARGSUSED*/
  963. static    void
  964. comment(command, args)
  965.     char    *command,
  966.         *args;
  967. {
  968.     /* nothing to do... */
  969. }
  970.  
  971. /*
  972.  * e_nick: does the /NICK command.  Records the users current nickname and
  973.  * sends the command on to the server 
  974.  */
  975. /*ARGSUSED*/
  976. static    void
  977. e_nick(command, args)
  978.     char    *command,
  979.         *args;
  980. {
  981.     char    *nick;
  982.  
  983.     if (!(nick = next_arg(args, &args)))
  984.     {
  985.         say("Your nickname is %s",
  986.             get_server_nickname(get_window_server(0)));
  987.         return;
  988.     }
  989.     if ((nick = check_nickname(nick)) != NULL)
  990.     {
  991.         send_to_server("NICK %s", nick);
  992.         if (get_server_version(from_server) == Server2_5)
  993.             add_to_whois_queue(nick, whois_nickname,
  994.                 NULL);
  995.     }
  996.     else
  997.         say("Bad nickname");
  998. }
  999.  
  1000. /* version: does the /VERSION command with some IRCII version stuff */
  1001. static    void
  1002. version(command, args)
  1003.     char    *command,
  1004.         *args;
  1005. {
  1006.     char    *host;
  1007.  
  1008.     if ((host = next_arg(args, &args)) != NULL)
  1009.         send_to_server("%s %s", command, host);
  1010.     else
  1011.     { 
  1012.         say("Client: ircII %s (internal version %s)", irc_version, internal_version);
  1013.         send_to_server("%s", command);
  1014.     }
  1015. }
  1016.  
  1017. /*
  1018.  * info: does the /INFO command.  I just added some credits
  1019.  * I updated most of the text -phone, feb 1993.
  1020.  */
  1021. static    void
  1022. info(command, args)
  1023.     char    *command,
  1024.         *args;
  1025. {
  1026.     if (!args || !*args)
  1027.     {
  1028.         say("ircii: originally written by Michael Sandrof");
  1029.         say("       versions 2.1 to 2.2pre7 by Troy Rollo");
  1030.         say("       development continued by matthew green");
  1031.         say("       e-mail: mrg@mame.mu.oz.au  irc: phone");
  1032.         say("       copyright (c) 1990-1994");
  1033.         say("       do a /help ircii copyright for the full copyright");
  1034.         say("       ircii includes software developed by the university");
  1035.         say("       of california, berkeley and its contributors");
  1036.         say("");
  1037.         say("major 2.6 helpers:");
  1038.         say("       \tNicolas Pioch        <poich@poly.polytechnique.fr>");
  1039.         say("       \tIan Frechette        <frechett@spot.colorado.edu>");
  1040.         say("       \tChris Williams       <cgw@unt.edu>");
  1041.         say("       \tJeff Grills          <jefftep@cs.utexas.edu>");
  1042.         say("");
  1043.         say("ircii contributors");
  1044.         say("");
  1045.         say("       \tMichael Sandrof       Mark T. Dameu");
  1046.         say("       \tStellan Klebom        Carl v. Loesch");
  1047.         say("       \tTroy Rollo            Martin  Friedrich");
  1048.         say("       \tMichael Weber         Bill Wisner");
  1049.         say("       \tRiccardo Facchetti    Stephen van den Berg");
  1050.         say("       \tVolker Paulsen        Kare Pettersson");
  1051.         say("       \tIan Frechette         Charles Hannum");
  1052.         say("       \tmatthew green         Christopher Williams");
  1053.         say("       \tJonathan Lemon        Brian Koehmstedt");
  1054.         say("       \tNicolas Pioch         Brian Fehdrau");
  1055.         say("       \tDarren Reed           Jeff Grills");
  1056.         say("       \tJeremy Nelson");
  1057.     }
  1058.     send_to_server("%s %s", command, args);
  1059. }
  1060.  
  1061. extern    void
  1062. ison_ison(notused, nicklist)
  1063.     char    *notused;
  1064.     char    *nicklist;
  1065. {
  1066.     if (do_hook(current_numeric, "%s", nicklist))
  1067.         put_it("%s Currently online: %s", numeric_banner(), nicklist);
  1068. }
  1069.  
  1070. static    void
  1071. ison(command, args)
  1072.     char    *command;
  1073.     char    *args;
  1074. {
  1075.     if (!args[strspn(args, " ")])
  1076.         args = get_server_nickname(from_server);
  1077.     add_ison_to_whois(args, ison_ison);
  1078.  
  1079. }
  1080.  
  1081. /*
  1082.  * userhost: Does the USERHOST command.  Need to split up the queries,
  1083.  * since the server will only reply to 5 at a time.
  1084.  */
  1085. static    void
  1086. userhost(command, args)
  1087.     char    *command;
  1088.     char    *args;
  1089. {
  1090.     int    n = 0,
  1091.         total = 0,
  1092.         userhost_cmd = 0;
  1093.     char    *nick;
  1094.  
  1095.     while ((nick = next_arg(args, &args)) != NULL)
  1096.     {
  1097.         int    len;
  1098.  
  1099.         ++total;
  1100.         len = strlen(nick);
  1101.         if (!my_strnicmp(nick, "-CMD", len))
  1102.         {
  1103.             if (total < 2)
  1104.             {
  1105.                 yell("userhost -cmd with no nick!");
  1106.                 return;
  1107.             }
  1108.             userhost_cmd = 1;
  1109.             break;
  1110.         }
  1111.         else
  1112.         {
  1113.             if (n++)
  1114.                 strmcat(buffer, " ", BIG_BUFFER_SIZE);
  1115.             else
  1116.                 *buffer = '\0';
  1117.             strmcat(buffer, nick, BIG_BUFFER_SIZE);
  1118.         }
  1119.     }
  1120.     if (n)
  1121.     {
  1122.         char    *the_list = (char *) 0;
  1123.         char    *s, *t;
  1124.         int    i;
  1125.  
  1126.         malloc_strcpy(&the_list, buffer);
  1127.         s = t = the_list;
  1128.         while (n)
  1129.         {
  1130.             for (i = 5; i && *s; s++)
  1131.                 if (' ' == *s)
  1132.                     i--, n--;
  1133.             if (' ' == *(s - 1))
  1134.                 *(s - 1) = '\0';
  1135.             else
  1136.                 n--;
  1137.             strcpy(buffer, t);
  1138.             t = s;
  1139.  
  1140.             if (userhost_cmd)
  1141.                 add_to_whois_queue(buffer, userhost_cmd_returned, "%s", args);
  1142.             else
  1143.                 add_to_whois_queue(buffer, USERHOST_USERHOST, 0);
  1144.         }
  1145.         new_free(&the_list);
  1146.     }
  1147.     else if (!total)
  1148.         /* Default to yourself.  */
  1149.         add_to_whois_queue(get_server_nickname(from_server), USERHOST_USERHOST, 0);
  1150. }
  1151.  
  1152. /*
  1153.  * whois: the WHOIS and WHOWAS commands.  This translates the 
  1154.  * to the whois handlers in whois.c 
  1155.  */
  1156. static    void
  1157. whois(command, args)
  1158.     char    *command,
  1159.         *args;
  1160. {
  1161.     if (args && *args)
  1162.         send_to_server("%s %s", command, args);
  1163.     else /* Default to yourself  -lynx */
  1164.         send_to_server("%s %s", command, get_server_nickname(from_server));
  1165. }
  1166.  
  1167. /*
  1168.  * who: the /WHO command. Parses the who switches and sets the who_mask and
  1169.  * whoo_stuff accordingly.  Who_mask and who_stuff are used in whoreply() in
  1170.  * parse.c 
  1171.  */
  1172. static    void
  1173. who(command, args)
  1174.     char    *command,
  1175.         *args;
  1176. {
  1177.     char    *arg,
  1178.         *channel = NULL;
  1179.     int    no_args = 1,
  1180.         len;
  1181.  
  1182.     who_mask = 0;
  1183.     new_free(&who_name);
  1184.     new_free(&who_host);
  1185.     new_free(&who_server);
  1186.     new_free(&who_file);
  1187.     new_free(&who_nick);
  1188.     new_free(&who_real);
  1189.     while ((arg = next_arg(args, &args)) != NULL)
  1190.     {
  1191.         no_args = 0;
  1192.         if ((*arg == '-') && (!isdigit(*(arg + 1))))
  1193.         {
  1194.             arg++;
  1195.             if ((len = strlen(arg)) == 0)
  1196.             {
  1197.                 say("Unknown or missing flag");
  1198.                 return;
  1199.             }
  1200.             if (my_strnicmp(arg, "operators", len) == 0)
  1201.                 who_mask |= WHO_OPS;
  1202.             else if (my_strnicmp(arg, "lusers", len) == 0)
  1203.                 who_mask |= WHO_LUSERS;
  1204.             else if (my_strnicmp(arg, "chops", len) == 0)
  1205.                 who_mask |= WHO_CHOPS;
  1206.             else if (my_strnicmp(arg, "hosts", len) == 0)
  1207.             {
  1208.                 if ((arg = next_arg(args, &args)) != NULL)
  1209.                 {
  1210.                     who_mask |= WHO_HOST;
  1211.                     malloc_strcpy(&who_host, arg);
  1212.                     channel = who_host;
  1213.                 }
  1214.                 else
  1215.                 {
  1216.                     say("WHO -HOSTS: missing arguement");
  1217.                     return;
  1218.                 }
  1219.             }
  1220.             else if (my_strnicmp(arg, "here", len) ==0)
  1221.                 who_mask |= WHO_HERE;
  1222.             else if (my_strnicmp(arg, "away", len) ==0)
  1223.                 who_mask |= WHO_AWAY;
  1224.             else if (my_strnicmp(arg, "servers", len) == 0)
  1225.             {
  1226.                 if ((arg = next_arg(args, &args)) != NULL)
  1227.                 {
  1228.                     who_mask |= WHO_SERVER;
  1229.                     malloc_strcpy(&who_server, arg);
  1230.                     channel = who_server;
  1231.                 }
  1232.                 else
  1233.                 {
  1234.                     say("WHO -SERVERS: missing arguement");
  1235.                     return;
  1236.                 }
  1237.             }
  1238.             else if (my_strnicmp(arg, "name", len) == 0)
  1239.             {
  1240.                 if ((arg = next_arg(args, &args)) != NULL)
  1241.                 {
  1242.                     who_mask |= WHO_NAME;
  1243.                     malloc_strcpy(&who_name, arg);
  1244.                     channel = who_name;
  1245.                 }
  1246.                 else
  1247.                 {
  1248.                     say("WHO -NAME: missing arguement");
  1249.                     return;
  1250.                 }
  1251.             }
  1252.             else if (my_strnicmp(arg, "realname", len) == 0)
  1253.             {
  1254.                 if ((arg = next_arg(args, &args)) != NULL)
  1255.                 {
  1256.                     who_mask |= WHO_REAL;
  1257.                     malloc_strcpy(&who_real, arg);
  1258.                     channel = who_real;
  1259.                 }
  1260.                 else
  1261.                 {
  1262.                     say("WHO -REALNAME: missing arguement");
  1263.                     return;
  1264.                 }
  1265.             }
  1266.             else if (my_strnicmp(arg, "nick", len) == 0)
  1267.             {
  1268.                 if ((arg = next_arg(args, &args)) != NULL)
  1269.                 {
  1270.                     who_mask |= WHO_NICK;
  1271.                     malloc_strcpy(&who_nick, arg);
  1272.                     channel = who_nick;
  1273.                 }
  1274.                 else
  1275.                 {
  1276.                     say("WHO -NICK: missing arguement");
  1277.                     return;
  1278.                 }
  1279.                 /* WHO -FILE by Martin 'Efchen' Friedrich */
  1280.             }
  1281.             else if (my_strnicmp(arg, "file", len) == 0)
  1282.             {
  1283.                 who_mask |= WHO_FILE;
  1284.                 if ((arg = next_arg(args, &args)) != NULL)
  1285.                 {
  1286.                     malloc_strcpy(&who_file, arg);
  1287.                 }
  1288.                 else
  1289.                 {
  1290.                     say("WHO -FILE: missing arguement");
  1291.                     return;
  1292.                 }
  1293.             }
  1294.             else
  1295.             {
  1296.                 say("Unknown or missing flag");
  1297.                 return;
  1298.             }
  1299.         }
  1300.         else if (strcmp(arg, "*") == 0)
  1301.         {
  1302.             channel = get_channel_by_refnum(0);
  1303.             if (!channel || *channel == '0')
  1304.  
  1305.             {
  1306.                 say("I wouldn't do that if I were you");
  1307.                 return;
  1308.             }
  1309.         }
  1310.         else
  1311.             channel = arg;
  1312.     }
  1313.     if (no_args)
  1314.         say("No argument specified");
  1315.     else
  1316.     {
  1317.         if (!channel && (who_mask&WHO_OPS))
  1318.             channel = "*.*";
  1319.         send_to_server("%s %s %c", command, channel ? channel :
  1320.                 empty_string, (who_mask & WHO_OPS) ?
  1321.                     'o' : '\0');
  1322.     }
  1323. }
  1324.  
  1325. /*
  1326.  * query: the /QUERY command.  Works much like the /MSG, I'll let you figure
  1327.  * it out.
  1328.  */
  1329. /*ARGSUSED*/
  1330. void
  1331. query(command, args)
  1332.     char    *command,
  1333.         *args;
  1334. {
  1335.     char    *nick,
  1336.         *rest;
  1337.  
  1338.     message_from(NULL, LOG_CURRENT);
  1339.     if ((nick = next_arg(args, &rest)) != NULL)
  1340.     {
  1341.         if (strcmp(nick, ".") == 0)
  1342.         {
  1343.             if (!(nick = sent_nick))
  1344.             {
  1345.                 say("You have not messaged anyone yet");
  1346.                 return;
  1347.             }
  1348.         }
  1349.         else if (strcmp(nick, ",") == 0)
  1350.         {
  1351.             if (!(nick = recv_nick))
  1352.             {
  1353.                 say("You have not recieved a message from \
  1354.                         anyone yet");
  1355.                 return;
  1356.             }
  1357.         }
  1358.         else if (strcmp(nick, "*") == 0)
  1359.             if (!(nick = get_channel_by_refnum(0)))
  1360.             {
  1361.                 say("You are not on a channel");
  1362.                 return;
  1363.             }
  1364.  
  1365. #ifndef _Windows
  1366.         if (*nick == '%')
  1367.         {
  1368.             if (is_process(nick) == 0)
  1369.             {
  1370.                 say("Invalid processes specification");
  1371.                 message_from(NULL, LOG_CRAP);
  1372.                 return;
  1373.             }
  1374.         }
  1375. #endif
  1376.         say("Starting conversation with %s", nick);
  1377.         set_query_nick(nick);
  1378.     }
  1379.     else
  1380.     {
  1381.         if (query_nick())
  1382.         {
  1383.             say("Ending conversation with %s", query_nick());
  1384.             set_query_nick(NULL);
  1385.         }
  1386.         else
  1387.             say("You aren't querying anyone!");
  1388.     }
  1389.     update_input(UPDATE_ALL);
  1390.     message_from(NULL, LOG_CRAP);
  1391. }
  1392.  
  1393. /*
  1394.  * away: the /AWAY command.  Keeps track of the away message locally, and
  1395.  * sends the command on to the server.
  1396.  */
  1397. static    void
  1398. away(command, args)
  1399.     char    *command,
  1400.         *args;
  1401. {
  1402.     int    len;
  1403.     char    *arg = NULL;
  1404.     int    flag = AWAY_ONE;
  1405.     int    i;
  1406.  
  1407.     if (*args)
  1408.     {
  1409.         if (*args == '-')
  1410.         {
  1411.             arg = index(args, ' ');
  1412.             if (arg)
  1413.                 *arg++ = '\0';
  1414.             else
  1415.                 arg = "";
  1416.             len = strlen(args);
  1417.             if (0 == my_strnicmp(args, "-ALL", len))
  1418.             {
  1419.                 flag = AWAY_ALL;
  1420.                 args = arg;
  1421.             }
  1422.             else if (0 == my_strnicmp(args, "-ONE", len))
  1423.             {
  1424.                 flag = AWAY_ONE;
  1425.                 args = arg;
  1426.             }
  1427.             else
  1428.             {
  1429.                 say("%s: %s unknown flag", command, args);
  1430.                 return;
  1431.             }
  1432.         }
  1433.     }
  1434.     if (flag == AWAY_ALL)
  1435.         if (*args)
  1436.         {
  1437.             away_set = 1;
  1438.             MarkAllAway(command, args);
  1439.         }
  1440.         else
  1441.         {
  1442.             away_set = 0;
  1443.             for(i = 0; (i < number_of_servers); i++)
  1444.                 if (server_list[i].whois_stuff.away)
  1445.                     new_free(&(server_list[i].away));
  1446.         }
  1447.     else
  1448.     {
  1449.         send_to_server("%s :%s", command, args);
  1450.         if (*args)
  1451.         {
  1452.             away_set = 1;
  1453.             malloc_strcpy(&(server_list[
  1454.                 curr_scr_win->server].away), args);
  1455.         }
  1456.         else
  1457.         {
  1458.             new_free(&(server_list[
  1459.                 curr_scr_win->server].away));
  1460.             away_set = 0;
  1461.             for(i = 0; (i < number_of_servers) && !away_set ; i++)
  1462.                 if (server_list[i].read != -1 &&
  1463.                         server_list[i].away)
  1464.                     away_set = 1;
  1465.         }
  1466.     }
  1467.     update_all_status();
  1468. }
  1469.  
  1470. /* e_quit: The /QUIT, /EXIT, etc command */
  1471. /*ARGSUSED*/
  1472. void
  1473. e_quit(command, args)
  1474.     char    *command,
  1475.         *args;
  1476. {
  1477.     int    max;
  1478.     int    i;
  1479.     char    *Reason;
  1480.  
  1481.     Reason = ((*args) ? args : "Leaving");
  1482.     max = server_list_size();
  1483.     for (i = 0; i < max; i++)
  1484.         if (is_server_connected(i))
  1485.         {
  1486.             from_server = i;
  1487.             send_to_server("QUIT :%s", Reason);
  1488.         }
  1489.     irc_exit();
  1490. }
  1491.  
  1492. /* flush: flushes all pending stuff coming from the server */
  1493. /*ARGSUSED*/
  1494. static    void
  1495. flush(command, args)
  1496.     char    *command,
  1497.         *args;
  1498. {
  1499.     if (get_int_var(HOLD_MODE_VAR))
  1500.     {
  1501.         while (curr_scr_win->held_lines)
  1502.             remove_from_hold_list(curr_scr_win);
  1503.         hold_mode((Window *) 0, OFF, 1);
  1504.     }
  1505.     say("Standby, Flushing server output...");
  1506.     flush_server();
  1507.     say("Done");
  1508. }
  1509.  
  1510. /* e_wall: used for WALL and WALLOPS */
  1511. static    void
  1512. e_wall(command, args)
  1513.     char    *command,
  1514.         *args;
  1515. {
  1516.     if (strcmp(command, "WALL") == 0)
  1517.     {    /* I hate this */
  1518.         message_from(NULL, LOG_WALL);
  1519.         if (!get_server_operator(from_server))
  1520.             put_it("## %s", args);
  1521.     }
  1522.     else
  1523.     {
  1524.         message_from(NULL, LOG_WALLOP);
  1525.         if (!get_server_flag(from_server, USER_MODE_W))
  1526.             put_it("!! %s", args);
  1527.     }
  1528.     if (!in_on_who)
  1529.         send_to_server("%s :%s", command, args);
  1530.     message_from(NULL, LOG_CRAP);
  1531. }
  1532.  
  1533. /*
  1534.  * e_privmsg: The MSG command, displaying a message on the screen indicating
  1535.  * the message was sent.  Also, this works for the NOTICE command. 
  1536.  */
  1537. static    void
  1538. e_privmsg(command, args)
  1539.     char    *command,
  1540.         *args;
  1541. {
  1542.     char    *nick;
  1543.  
  1544.     if ((nick = next_arg(args, &args)) != NULL)
  1545.     {
  1546.         if (strcmp(nick, ".") == 0)
  1547.         {
  1548.             if (!(nick = sent_nick))
  1549.             {
  1550.                 say("You have not sent a message to anyone yet");
  1551.                 return;
  1552.             }
  1553.         }
  1554.  
  1555.         else if (strcmp(nick, ",") == 0)
  1556.         {
  1557.             if (!(nick = recv_nick))
  1558.             {
  1559.                 say("You have not received a message from anyone yet");
  1560.                 return;
  1561.             }
  1562.         }
  1563.         else if (!strcmp(nick, "*"))
  1564.             if (!(nick = get_channel_by_refnum(0)))
  1565.                 nick = "0";
  1566.         send_text(nick, args, command);
  1567.     }
  1568.     else
  1569.         say("You must specify a nickname or channel!");
  1570. }
  1571.  
  1572. /*
  1573.  * quote: handles the QUOTE command.  args are a direct server command which
  1574.  * is simply send directly to the server 
  1575.  */
  1576. /*ARGSUSED*/
  1577. static    void    quote(command, args)
  1578. char    *command,
  1579.     *args;
  1580. {
  1581.     if (!in_on_who)
  1582.         send_to_server("%s", args);
  1583. }
  1584.  
  1585. /* clear: the CLEAR command.  Figure it out */
  1586. /*ARGSUSED*/
  1587. static    void
  1588. clear(command, args)
  1589.     char    *command,
  1590.         *args;
  1591. {
  1592.     char    *arg;
  1593.     int    all = 0,
  1594.         unhold = 0;
  1595.  
  1596.     while ((arg = next_arg(args, &args)) != NULL)
  1597.     {
  1598.     /* -ALL and ALL here becuase the help files used to be wrong */
  1599.         if (!my_strnicmp(arg, "ALL", strlen(arg))
  1600.                 || !my_strnicmp(arg, "-ALL", strlen(arg)))
  1601.             all = 1;
  1602.         else if (!my_strnicmp(arg, "-UNHOLD", strlen(arg)))
  1603.             unhold = 1;
  1604.         else
  1605.             say("Unknown flag: %s", arg);
  1606.     }
  1607.     if (all)
  1608.         clear_all_windows(unhold);
  1609.     else
  1610.     {
  1611.         if (unhold)
  1612.             hold_mode((Window *) 0, OFF, 1);
  1613.         clear_window_by_refnum(0);
  1614.     }
  1615.     update_input(UPDATE_JUST_CURSOR);
  1616. }
  1617.  
  1618. /*
  1619.  * send_comm: the generic command function.  Uses the full command name found
  1620.  * in 'command', combines it with the 'args', and sends it to the server 
  1621.  */
  1622. static    void
  1623. send_comm(command, args)
  1624.     char    *command,
  1625.         *args;
  1626. {
  1627.     if (args && *args)
  1628.         send_to_server("%s %s", command, args);
  1629.     else
  1630.         send_to_server("%s", command);
  1631. }
  1632.  
  1633.  
  1634. static    void
  1635. send_topic(command, args)
  1636.     char    *command,
  1637.         *args;
  1638. {
  1639.     char    *arg;
  1640.     char    *arg2;
  1641.  
  1642.     if ((arg = next_arg(args, &args)) != NULL)
  1643.     {
  1644.         if (is_channel(arg))
  1645.         {
  1646.             if ((arg2 = next_arg(args, &args)) != NULL)
  1647.                 send_to_server("%s %s :%s %s", command, arg,
  1648.                         arg2, args);
  1649.             else
  1650.                 send_to_server("%s %s", command, arg);
  1651.         }
  1652.         else
  1653.             send_to_server("%s :%s %s", command, arg, args);
  1654.     }
  1655.     else
  1656.         send_to_server("%s", command);
  1657. }
  1658.  
  1659. static    void
  1660. send_2comm(command, args)
  1661.     char    *command,
  1662.         *args;
  1663. {
  1664.     char    *reason;
  1665.  
  1666.     if ((reason = index(args, ' ')) != NULL)
  1667.         *reason++ = '\0';
  1668.     else
  1669.         reason = empty_string;
  1670.  
  1671.     if (reason && *reason)
  1672.         send_to_server("%s %s :%s", command, args, reason);
  1673.     else
  1674.         send_to_server("%s %s", command, args);
  1675. }
  1676.  
  1677. /*
  1678.  * send_kick: sends a kick message to the server.  Works properly with
  1679.  * kick comments.
  1680.  */
  1681.  
  1682. static    void
  1683. send_kick(command, args)
  1684.     char    *command,
  1685.         *args;
  1686. {
  1687.     char    *kickee,
  1688.         *comment;
  1689.  
  1690.     if ((kickee = index(args, ' ')) != NULL)
  1691.         *(kickee++) = (char) 0;
  1692.     else 
  1693.         kickee = index(args, (char) 0);
  1694.  
  1695.     if ((comment = index(kickee, ' ')) != NULL)
  1696.         *(comment++) = (char) 0;
  1697.     else 
  1698.         comment = index(kickee, (char) 0);
  1699.  
  1700.     if (strcmp(args, "*") == 0)
  1701.         send_to_server("%s %s %s :%s", command,
  1702.                 get_channel_by_refnum(0), kickee, comment);
  1703.     else
  1704.         send_to_server("%s %s %s :%s", command, args, kickee, comment);
  1705. }
  1706.  
  1707. /*
  1708.  * send_channel_com: does the same as send_com for command where the first
  1709.  * argument is a channel name.  If the first argument is *, it is expanded
  1710.  * to the current channel (a la /WHO).
  1711.  */
  1712. static    void
  1713. send_channel_com(command, args)
  1714.     char    *command,
  1715.         *args;
  1716. {
  1717.     char    *ptr,
  1718.         *s;
  1719.  
  1720.     if ((ptr = index(args, ' ')) != NULL)
  1721.         *(ptr++) = (char) 0;
  1722.     else
  1723.         ptr = index(args, (char) 0);
  1724.  
  1725.     if (!strcmp(args, "*"))
  1726.     {
  1727.         if ((s = get_channel_by_refnum(0)) != NULL)
  1728.             send_to_server("%s %s %s", command, s, ptr);
  1729.         else
  1730.             say("You aren't on a channel in this window");
  1731.     }
  1732.     else
  1733.         send_to_server("%s %s %s", command, args, ptr);
  1734. }
  1735.  
  1736. /*
  1737.  * send_text: Sends the line of text to whomever the user is currently
  1738.  * talking.  If they are quering someone, it goes to that user, otherwise
  1739.  * it's the current channel.  Some tricky parameter business going on. If
  1740.  * nick is null (as if you had typed "/ testing" on the command line) the
  1741.  * line is sent to your channel, and the command parameter is never used. If
  1742.  * nick is not null, and command is null, the line is sent as a PRIVMSG.  If
  1743.  * nick is not null and command is not null, the message is sent using
  1744.  * command.  Currently, only NOTICEs and PRIVMSGS work. 
  1745.  * fixed to not be anal about "/msg foo,bar foobar" -phone
  1746.  */
  1747. void
  1748. send_text(org_nick, line, command)
  1749.     char    *org_nick;
  1750.     char    *line;
  1751.     char    *command;
  1752. {
  1753.     char    *key,
  1754.         *ptr,
  1755.         *free_nick,
  1756.         *nick = NULL;
  1757.     int    lastlog_level,
  1758.         list_type,
  1759.         old_server;
  1760.     int    check_away;
  1761.     char    the_thing;
  1762.     char    *query_command = NULL;
  1763.     char    nick_list[IRCD_BUFFER_SIZE];
  1764.     int    do_final_send = 0;
  1765.  
  1766.     *nick_list = '\0';
  1767.     malloc_strcpy(&nick, org_nick);
  1768.     free_nick = ptr = nick;
  1769.     while ((nick = ptr) != NULL)
  1770.     {
  1771.         if ((ptr = index(nick, ',')) != NULL)
  1772.             *(ptr++) = (char) 0;
  1773.         if (!*nick)
  1774.             continue;
  1775. #ifndef _Windows
  1776.         if (is_process(nick))
  1777.         {
  1778.             int    i;
  1779.  
  1780.             if ((i = get_process_index(&nick)) == -1)
  1781.                 say("Invalid process specification");
  1782.             else
  1783.                 text_to_process(i, line, 1);
  1784.             continue;
  1785.         }
  1786. #endif
  1787.         if (!*line)
  1788.             continue; /* lynx */
  1789.         if (in_on_who)
  1790.         {
  1791.             say("You may not send messages from ON WHO, ON WHOIS, or ON JOIN");
  1792.             continue;
  1793.         }
  1794.         if (doing_privmsg)
  1795.             command    = "NOTICE";
  1796.         /* Query quote -lynx */
  1797.         if (strcmp(nick, "\"") == 0) /* quote */
  1798.         {
  1799.             send_to_server("%s", line);
  1800.             continue;
  1801.         }
  1802.         if (*nick == '=') /* DCC chat */
  1803.         {
  1804.             old_server = from_server;
  1805.             from_server = -1;
  1806.             dcc_chat_transmit(nick + 1, line);
  1807.             from_server = old_server;
  1808.             continue;
  1809.         }
  1810.         if (*nick == '@') /* DCC talk */
  1811.         {
  1812.             old_server = from_server;
  1813.             from_server = -1;
  1814.             dcc_message_transmit(nick + 1, line, DCC_TALK, 1);
  1815.             from_server = old_server;
  1816.             continue;
  1817.         }
  1818.         if (*nick == '/') /* Command */
  1819.         {
  1820.             malloc_strcpy(&query_command, nick);
  1821.             malloc_strcat(&query_command, " ");
  1822.             malloc_strcat(&query_command, line);
  1823.             parse_command(query_command, 0, empty_string);
  1824.             new_free(&query_command);
  1825.             continue;
  1826.         }
  1827.         switch (send_text_flag)
  1828.         {
  1829.         case MSG_LIST:
  1830.             command = "NOTICE";
  1831.             break;
  1832.         case NOTICE_LIST:
  1833.             say("You cannot send a message from a NOTICE");
  1834.             new_free(&free_nick);
  1835.             return;
  1836.         }
  1837.         if (is_channel(nick))
  1838.         {
  1839.             int    current;
  1840.  
  1841.             current = is_current_channel(nick, 0);
  1842.             if (!command || strcmp(command, "NOTICE"))
  1843.             {
  1844.                 command = "PRIVMSG";
  1845.                 lastlog_level = set_lastlog_msg_level(LOG_PUBLIC);
  1846.                 message_from(nick, LOG_PUBLIC);
  1847.                 list_type = SEND_PUBLIC_LIST;
  1848.                 the_thing = '>';
  1849.             }
  1850.             else
  1851.             {
  1852.                 lastlog_level = set_lastlog_msg_level(LOG_NOTICE);
  1853.                 message_from(nick, LOG_NOTICE);
  1854.                 list_type = SEND_NOTICE_LIST;
  1855.                 the_thing = '-';
  1856.             }
  1857.             if (do_hook(list_type, "%s %s", nick, line))
  1858.             {
  1859.                 if (current)
  1860.                     put_it("%c %s", the_thing, line);
  1861.                 else
  1862.                     put_it("%c%s> %s", the_thing, nick,
  1863.                         line);
  1864.             }
  1865.             set_lastlog_msg_level(lastlog_level);
  1866.             if ((key = is_crypted(nick)) != 0)
  1867.             {
  1868.                 char    *crypt_line;
  1869.  
  1870.                 if ((crypt_line = crypt_msg(line, key, 1)))
  1871.                     send_to_server("%s %s :%s", command, nick, crypt_line);
  1872.                 new_free(&crypt_line);
  1873.                 continue;
  1874.             }
  1875.             if (!in_on_who)
  1876.             {
  1877.                 if (*nick_list)
  1878.                 {
  1879.                     strcat(nick_list, ",");
  1880.                     strcat(nick_list, nick);
  1881.                 }
  1882.                 else
  1883.                     strcpy(nick_list, nick);
  1884.             }
  1885.             do_final_send = 1;
  1886.         }
  1887.         else
  1888.         {
  1889.             if (!command || strcmp(command, "NOTICE"))
  1890.             {
  1891.                 lastlog_level = set_lastlog_msg_level(LOG_MSG);
  1892.                 command = "PRIVMSG";
  1893.                 message_from(nick, LOG_MSG);
  1894.                 list_type = SEND_MSG_LIST;
  1895.                 the_thing = '*';
  1896.             }
  1897.             else
  1898.             {
  1899.                 lastlog_level = set_lastlog_msg_level(LOG_NOTICE);
  1900.                 message_from(nick, LOG_NOTICE);
  1901.                 list_type = SEND_NOTICE_LIST;
  1902.                 the_thing = '-';
  1903.             }
  1904.             if (window_display && do_hook(list_type, "%s %s", nick, line))
  1905.                 put_it("-> %c%s%c %s", the_thing, nick, the_thing, line);
  1906.             if ((key = is_crypted(nick)) != NULL)
  1907.             {
  1908.                 char    *crypt_line;
  1909.  
  1910.                 if ((crypt_line = crypt_msg(line, key, 1)))
  1911.                     send_to_server("%s %s :%s", command ? command : "PRIVMSG", nick, crypt_line);
  1912.                 new_free(&crypt_line);
  1913.                 continue;
  1914.             }
  1915.             set_lastlog_msg_level(lastlog_level);
  1916.  
  1917.             if (!in_on_who)
  1918.             {
  1919.                 if (*nick_list)
  1920.                 {
  1921.                     strcat(nick_list, ",");
  1922.                     strcat(nick_list, nick);
  1923.                 }
  1924.                 else
  1925.                     strcpy(nick_list, nick);
  1926.             }
  1927.  
  1928.             if (get_int_var(WARN_OF_IGNORES_VAR) && (is_ignored(nick, IGNORE_MSGS) == IGNORED))
  1929.                 say("Warning: You are ignoring private messages from %s", nick);
  1930.  
  1931.             malloc_strcpy(&sent_nick, nick);
  1932.             if (check_away && server_list[curr_scr_win->server].away && get_int_var(AUTO_UNMARK_AWAY_VAR))
  1933.             {
  1934.                 check_away = 1;
  1935.                 away("AWAY", empty_string);
  1936.             }
  1937.             do_final_send = 1;
  1938.         }
  1939.     }
  1940.  
  1941.     malloc_strcpy(&sent_body, line);
  1942.     if (do_final_send)
  1943.         send_to_server("%s %s :%s", command ? command : "PRIVMSG", nick_list, line);
  1944.     message_from(NULL, LOG_CRAP);
  1945.     new_free(&free_nick);
  1946. }
  1947.  
  1948. void
  1949. do_send_text(command, args)
  1950.     char    *command,
  1951.         *args;
  1952. {
  1953.     char    *tmp;
  1954.  
  1955.     if (command)
  1956.         tmp = get_channel_by_refnum(0);
  1957.     else
  1958.         tmp = get_target_by_refnum(0);
  1959.     send_text(tmp, args, NULL);
  1960. }
  1961.  
  1962. /*
  1963.  * command_completion: builds lists of commands and aliases that match the
  1964.  * given command and displays them for the user's lookseeing 
  1965.  */
  1966. void
  1967. command_completion()
  1968. {
  1969.     int    do_aliases;
  1970.     int    cmd_cnt,
  1971.         alias_cnt,
  1972.         i,
  1973.         c,
  1974.         len;
  1975.     char    **aliases = NULL;
  1976.     char    *line = NULL,
  1977.         *com,
  1978.         *cmdchars,
  1979.         *rest,
  1980.         firstcmdchar = '/';
  1981.     IrcCommand    *command;
  1982.  
  1983.     malloc_strcpy(&line, get_input());
  1984.     if ((com = next_arg(line, &rest)) != NULL)
  1985.     {
  1986.         if (!(cmdchars = get_string_var(CMDCHARS_VAR)))
  1987.             cmdchars = DEFAULT_CMDCHARS;
  1988.         if (index(cmdchars, *com))
  1989.         {
  1990.             firstcmdchar = *cmdchars;
  1991.             com++;
  1992.             if (*com && index(cmdchars, *com))
  1993.             {
  1994.                 do_aliases = 0;
  1995.                 alias_cnt = 0;
  1996.                 com++;
  1997.             }
  1998.             else
  1999.                 do_aliases = 1;
  2000.             upper(com);
  2001.             if (do_aliases)
  2002.                 aliases = match_alias(com, &alias_cnt,
  2003.                     COMMAND_ALIAS);
  2004.             if ((command = find_command(com, &cmd_cnt)) != NULL)
  2005.             {
  2006.                 if (cmd_cnt < 0)
  2007.                     cmd_cnt *= -1;
  2008.                 /* special case for the empty string */
  2009.  
  2010.                 if (*(command[0].name) == (char) 0)
  2011.                 {
  2012.                     command++;
  2013.                     cmd_cnt = NUMBER_OF_COMMANDS;
  2014.                 }
  2015.             }
  2016.             if ((alias_cnt == 1) && (cmd_cnt == 0))
  2017.             {
  2018.                 sprintf(buffer, "%c%s %s", firstcmdchar,
  2019.                     aliases[0], rest);
  2020.                 set_input(buffer);
  2021.                 new_free(&(aliases[0]));
  2022.                 new_free(&aliases);
  2023.                 update_input(UPDATE_ALL);
  2024.             }
  2025.             else if (((cmd_cnt == 1) && (alias_cnt == 0)) ||
  2026.                 ((cmd_cnt == 1) && (alias_cnt == 1) &&
  2027.                 (strcmp(aliases[0], command[0].name) == 0)))
  2028.             {
  2029.                 sprintf(buffer, "%c%s%s %s", firstcmdchar,
  2030.                     do_aliases ? "" : &firstcmdchar,
  2031.                     command[0].name, rest);
  2032.                 set_input(buffer);
  2033.                 update_input(UPDATE_ALL);
  2034.             }
  2035.             else
  2036.             {
  2037.                 *buffer = (char) 0;
  2038.                 if (command)
  2039.                 {
  2040.                     say("Commands:");
  2041.                     strmcpy(buffer, "\t", BIG_BUFFER_SIZE);
  2042.                     c = 0;
  2043.                     for (i = 0; i < cmd_cnt; i++)
  2044.                     {
  2045.                         strmcat(buffer, command[i].name,
  2046.                             BIG_BUFFER_SIZE);
  2047.                         for (len =
  2048.                             strlen(command[i].name);
  2049.                             len < 15; len++)
  2050.                             strmcat(buffer, " ",
  2051.                                 BIG_BUFFER_SIZE);
  2052.                         if (++c == 4)
  2053.                         {
  2054.                             say("%s", buffer);
  2055.                             strmcpy(buffer, "\t",
  2056.                                 BIG_BUFFER_SIZE);
  2057.                             c = 0;
  2058.                         }
  2059.                     }
  2060.                     if (c)
  2061.                         say("%s", buffer);
  2062.                 }
  2063.                 if (aliases)
  2064.                 {
  2065.                     say("Aliases:");
  2066.                     strmcpy(buffer, "\t", BIG_BUFFER_SIZE);
  2067.                     c = 0;
  2068.                     for (i = 0; i < alias_cnt; i++)
  2069.                     {
  2070.                         strmcat(buffer, aliases[i],
  2071.                             BIG_BUFFER_SIZE);
  2072.                         for (len = strlen(aliases[i]);
  2073.                                 len < 15; len++)
  2074.                             strmcat(buffer, " ",
  2075.                                 BIG_BUFFER_SIZE);
  2076.                         if (++c == 4)
  2077.                         {
  2078.                             say("%s", buffer);
  2079.                             strmcpy(buffer, "\t",
  2080.                                 BIG_BUFFER_SIZE);
  2081.                             c = 0;
  2082.                         }
  2083.                         new_free(&(aliases[i]));
  2084.                     }
  2085.                     if (strlen(buffer) > 1)
  2086.                         say("%s", buffer);
  2087.                     new_free(&aliases);
  2088.                 }
  2089.                 if (!*buffer)
  2090.                     term_beep();
  2091.             }
  2092.         }
  2093.         else
  2094.             term_beep();
  2095.     }
  2096.     else
  2097.         term_beep();
  2098.     new_free(&line);
  2099. }
  2100.  
  2101. /*
  2102.  * parse_line: This is the main parsing routine.  It should be called in
  2103.  * almost all circumstances over parse_command().
  2104.  *
  2105.  * parse_line breaks up the line into commands separated by unescaped
  2106.  * semicolons if we are in non interactive mode. Otherwise it tries to leave
  2107.  * the line untouched.
  2108.  *
  2109.  * Currently, a carriage return or newline breaks the line into multiple
  2110.  * commands too. This is expected to stop at some point when parse_command
  2111.  * will check for such things and escape them using the ^P convention.
  2112.  * We'll also try to check before we get to this stage and escape them before
  2113.  * they become a problem.
  2114.  *
  2115.  * Other than these two conventions the line is left basically untouched.
  2116.  */
  2117. void
  2118. parse_line(name, org_line, args, hist_flag, append_flag)
  2119.     char    *name,
  2120.         *org_line,
  2121.         *args;
  2122.     int    hist_flag,
  2123.         append_flag;
  2124. {
  2125.     char    *line = NULL,
  2126.         *free_line,
  2127.         *stuff,
  2128.         *buffer,
  2129.         *s,
  2130.         *t;
  2131.     int    args_flag;
  2132.  
  2133.     malloc_strcpy(&line, org_line);
  2134.     free_line = line;
  2135.     args_flag = 0;
  2136.     if (!*line)
  2137.         do_send_text(NULL, empty_string);
  2138.     else if (args)
  2139.         do
  2140.         {
  2141.             stuff = expand_alias(name, line, args, &args_flag,
  2142.                     &line);
  2143.             if (!line && append_flag && !args_flag && args && *args)
  2144.             {
  2145.                 buffer = (char *) new_malloc(BIG_BUFFER_SIZE+1);
  2146.                 strmcpy(buffer, stuff, BIG_BUFFER_SIZE);
  2147.                 strmcat(buffer, " ", BIG_BUFFER_SIZE);
  2148.                 strmcat(buffer, args, BIG_BUFFER_SIZE);
  2149.                 new_free(&stuff);
  2150.                 stuff = buffer;
  2151.             }
  2152.             parse_command(stuff, hist_flag, args);
  2153.             new_free(&stuff);
  2154.         }
  2155.         while(line);
  2156.     else
  2157.     {
  2158.         if (load_depth)
  2159.             parse_command(line, hist_flag, args);
  2160.         else
  2161.             for (;(s = line);)
  2162.             {
  2163.                 if ((t = sindex(line, "\r\n")) != NULL)
  2164.                 {
  2165.                     *t++ = '\0';
  2166.                     line = t;
  2167.                 }
  2168.                 else
  2169.                     line = NULL;
  2170.                 parse_command(s, hist_flag, args);
  2171.             }
  2172.     }
  2173.     new_free(&free_line);
  2174.     return;
  2175. }
  2176.  
  2177. /*
  2178.  * parse_command: parses a line of input from the user.  If the first
  2179.  * character of the line is equal to irc_variable[CMDCHAR_VAR].value, the
  2180.  * line is used as an irc command and parsed appropriately.  If the first
  2181.  * character is anything else, the line is sent to the current channel or to
  2182.  * the current query user.  If hist_flag is true, commands will be added to
  2183.  * the command history as appropriate.  Otherwise, parsed commands will not
  2184.  * be added. 
  2185.  *
  2186.  * Parse_command() only parses a single command.In general, you will want to use
  2187.  * parse_line() to execute things.Parse command recognized no quoted
  2188.  * characters or anything(beyond those specific for a given command being
  2189.  * executed). 
  2190.  */
  2191. void
  2192. parse_command(line, hist_flag, sub_args)
  2193.     char    *line;
  2194.     int    hist_flag;
  2195.     char    *sub_args;
  2196. {
  2197.     static    unsigned int     level = 0;
  2198.     unsigned int    display,
  2199.             old_display_var;
  2200.     char    *cmdchars,
  2201.         *com,
  2202.         *this_cmd = NULL;
  2203.     int    args_flag,
  2204.         add_to_hist,
  2205.         cmdchar_used;
  2206.  
  2207.     if (!line || !*line)
  2208.         return;
  2209.     if (get_int_var(DEBUG_VAR) & DEBUG_COMMANDS)
  2210.         yell("Executing [%d] %s", level, line);
  2211.     level++;
  2212.     if (!(cmdchars = get_string_var(CMDCHARS_VAR)))
  2213.         cmdchars = DEFAULT_CMDCHARS;
  2214.     malloc_strcpy(&this_cmd, line);
  2215.     add_to_hist = 1;
  2216.     if (index(cmdchars, *line))
  2217.     {
  2218.         cmdchar_used = 1;
  2219.         com = line + 1;
  2220.     }
  2221.     else
  2222.     {
  2223.         cmdchar_used = 0;
  2224.         com = line;
  2225.     }
  2226.     /*
  2227.      * always consider input a command unless we are in interactive mode
  2228.      * and command_mode is off.   -lynx
  2229.      */
  2230.     if (hist_flag && !cmdchar_used && !get_int_var(COMMAND_MODE_VAR))
  2231.     {
  2232.         do_send_text(NULL, line);
  2233.         if (hist_flag && add_to_hist)
  2234.         {
  2235.             add_to_history(this_cmd);
  2236.             set_input(empty_string);
  2237.         }
  2238.         /* Special handling for ' and : */
  2239.     }
  2240.     else if (*com == '\'' && get_int_var(COMMAND_MODE_VAR))
  2241.     {
  2242.         do_send_text(NULL, line+1);
  2243.         if (hist_flag && add_to_hist)
  2244.         {
  2245.             add_to_history(this_cmd);
  2246.             set_input(empty_string);
  2247.         }
  2248.     }
  2249. #if 0 /* ':' is the no-op command. */
  2250.     else if (*com == ':' && get_int_var(COMMAND_MODE_VAR))
  2251.     {
  2252.         me(NULL, line+1);
  2253.         if (hist_flag && add_to_hist)
  2254.         {
  2255.             add_to_history(this_cmd);
  2256.             set_input(empty_string);
  2257.         }
  2258.     }
  2259. #endif
  2260.     else if (*com == '@')
  2261.     {
  2262.         /* This kludge fixes a memory leak */
  2263.         char    *tmp;
  2264.  
  2265.         tmp = parse_inline(line + 1, sub_args, &args_flag);
  2266.         if (tmp)
  2267.             new_free(&tmp);
  2268.         if (hist_flag && add_to_hist)
  2269.         {
  2270.             add_to_history(this_cmd);
  2271.             set_input(empty_string);
  2272.         }
  2273.     }
  2274.     else
  2275.     {
  2276.         char    *rest,
  2277.             *alias = NULL,
  2278.             *alias_name;
  2279.         int    cmd_cnt,
  2280.             alias_cnt;
  2281.         IrcCommand    *command; /* = (IrcCommand *) 0 */
  2282.  
  2283.         display = window_display;
  2284.         old_display_var = (unsigned) get_int_var(DISPLAY_VAR);
  2285.         if ((rest = (char *) index(com, ' ')) != NULL)
  2286.             *(rest++) = (char) 0;
  2287.         else
  2288.             rest = empty_string;
  2289.         upper(com);
  2290.  
  2291.         /* first, check aliases */
  2292.         if (*com && index(cmdchars, *com))
  2293.         {
  2294.             alias_cnt = 0;
  2295.             com++;
  2296.             if (*com == '^')
  2297.             {
  2298.                 com++;
  2299.                 window_display = 0;
  2300.             }
  2301.         }
  2302.         else{
  2303.             if (*com == '^')
  2304.             {
  2305.                 com++;
  2306.                 window_display = 0;
  2307.             }
  2308.             alias = get_alias(COMMAND_ALIAS, com, &alias_cnt,
  2309.                 &alias_name);
  2310.         }
  2311.         if (alias && (alias_cnt == 0))
  2312.         {
  2313.             if (hist_flag && add_to_hist)
  2314.             {
  2315.                 add_to_history(this_cmd);
  2316.                 set_input(empty_string);
  2317.             }
  2318.             execute_alias(alias_name, alias, rest);
  2319.             new_free(&alias_name);
  2320.         }
  2321.         else
  2322.         {
  2323.             /* History */
  2324.             if (*com == '!')
  2325.             {
  2326.                 if ((com = do_history(com + 1, rest)) != NULL)
  2327.                 {
  2328.                     if (level == 1)
  2329.                     {
  2330.                         set_input(com);
  2331.                         update_input(UPDATE_ALL);
  2332.                     }
  2333.                     else
  2334.                         parse_command(com, 0, sub_args);
  2335.                     new_free(&com);
  2336.                 }
  2337.                 else
  2338.                     set_input(empty_string);
  2339.                 /* add_to_hist = 0;   -- unused anyway */
  2340.             }
  2341.             else
  2342.             {
  2343.                 if (hist_flag && add_to_hist)
  2344.                 {
  2345.                     add_to_history(this_cmd);
  2346.                     set_input(empty_string);
  2347.                 }
  2348.                 command = find_command(com, &cmd_cnt);
  2349.                 if ((command && (cmd_cnt < 0)) ||
  2350.                         ((alias_cnt == 0) && (cmd_cnt
  2351.                             == 1)))
  2352.                 {
  2353.                     if (command->func)
  2354.                         command->func(
  2355.                             command->server_func,
  2356.                             rest, sub_args);
  2357.                     else
  2358.                         say("%s: command disabled",
  2359.                             command->name);
  2360.                 }
  2361.                 else if (alias && (alias_cnt == 1) &&
  2362.                     (cmd_cnt == 1) &&
  2363.                     (strcmp(alias_name, command[0].name) == 0))
  2364.                     execute_alias(alias_name, alias, rest);
  2365.                 else if ((alias_cnt + cmd_cnt) > 1)
  2366.                     say("Ambiguous command: %s", com);
  2367.                 else if (alias && (alias_cnt == 1))
  2368.                     execute_alias(alias_name, alias, rest);
  2369.                 else if (!my_stricmp(com, nickname))
  2370.                         /* nick = /me  -lynx */
  2371.                     me(NULL, rest);
  2372.                 else
  2373.                     say("Unknown command: %s", com);
  2374.             }
  2375.             if (alias)
  2376.                 new_free(&alias_name);
  2377.         }
  2378.         if (old_display_var != get_int_var(DISPLAY_VAR))
  2379.             window_display = get_int_var(DISPLAY_VAR);
  2380.         else
  2381.             window_display = display;
  2382.     }
  2383.     new_free(&this_cmd);
  2384.     level--;
  2385. }
  2386.  
  2387. /*
  2388.  * load: the /LOAD command.  Reads the named file, parsing each line as
  2389.  * though it were typed in (passes each line to parse_command). 
  2390.  */
  2391. /*ARGSUSED*/
  2392. void
  2393. load(command, args)
  2394.     char    *command,
  2395.         *args;
  2396. {
  2397.     FILE    *fp;
  2398.     char    *filename,
  2399.         *expanded = NULL;
  2400.     int    flag = 0;
  2401.     struct    stat    stat_buf;
  2402.     int    paste_level = 0;
  2403.     char    *start,
  2404.         *current_row = NULL;
  2405.     define_big_buffer(buffer);
  2406.     int    no_semicolon = 1;
  2407.     char    *irc_path;
  2408.     int    display;
  2409. #ifdef ZCAT
  2410.     char    *temp;
  2411.     char    *expand_z = NULL;
  2412.     int    exists;
  2413. #endif
  2414.  
  2415.     irc_path = get_string_var(LOAD_PATH_VAR);
  2416.     if (!irc_path)
  2417.     {
  2418.         say("LOAD_PATH has not been set");
  2419.         free_big_buffer(buffer);
  2420.         return;
  2421.     }
  2422.  
  2423.     if (load_depth == MAX_LOAD_DEPTH)
  2424.     {
  2425.         say("No more than %d levels of LOADs allowed", MAX_LOAD_DEPTH);
  2426.         free_big_buffer(buffer);
  2427.         return;
  2428.     }
  2429.     load_depth++;
  2430.     status_update(0);
  2431. #ifdef DAEMON_UID
  2432.     if (getuid() == DAEMON_UID)
  2433.     {
  2434.         say("You may only load your SAVED file");
  2435.         filename = ircrc_file;
  2436.     }
  2437.     else
  2438. #endif /* DAEMON_UID */
  2439.         while ((filename = next_arg(args, &args)) != NULL)
  2440.         {
  2441.             if (my_strnicmp(filename, "-args", strlen(filename)) == 0)
  2442.                 flag = 1;
  2443.             else
  2444.                 break;
  2445.         }
  2446.     if (filename)
  2447.     {
  2448.         if ((expanded = expand_twiddle(filename)) != NULL)
  2449.         {
  2450. #ifdef ZCAT
  2451.             /* Handle both <expanded> and <expanded>.Z */
  2452.             temp = &(expanded[strlen(expanded) - sizeof(ZSUFFIX)]);
  2453.             if (strcmp(temp, ZSUFFIX))
  2454.             {
  2455.                 malloc_strcpy(&expand_z, expanded);
  2456.                 malloc_strcat(&expand_z, ZSUFFIX);
  2457.             }
  2458. #endif /*ZCAT*/
  2459.             if (!IS_FULL_PATH(expanded))
  2460.             {
  2461. #ifdef ZCAT
  2462.                 if (!(filename = path_search(expanded,
  2463.                     irc_path)))
  2464.                     filename = path_search(expand_z,
  2465.                         irc_path);
  2466.                 if (!filename)
  2467. #else
  2468.                     if (!(filename = path_search(expanded,
  2469.                         irc_path)))
  2470. #endif /*ZCAT*/
  2471.                     {
  2472.                         say("%s: File not found",
  2473.                             expanded);
  2474.                         status_update(1);
  2475.                         load_depth--;
  2476. #ifdef ZCAT
  2477.                         new_free(&expand_z);
  2478. #endif /* ZCAT */
  2479.                         new_free(&expanded);
  2480.                         free_big_buffer(buffer);
  2481.                         return;
  2482.                     }
  2483.                     else
  2484.                         malloc_strcpy(&expanded, filename);
  2485.             }
  2486. #ifdef ZCAT
  2487.             if ((exists = stat_file(expanded, &stat_buf)) == -1)
  2488.                 if (!(exists = stat_file(expand_z, &stat_buf)))
  2489.                     expanded = expand_z;
  2490.                 else
  2491.                     new_free(&expand_z);
  2492.             if (exists == 0)
  2493. #else
  2494.                 if (!stat_file(expanded, &stat_buf))
  2495. #endif /*ZCAT*/
  2496.                 {
  2497.                     if (stat_buf.st_mode & S_IFDIR)
  2498.                     {
  2499.                         say("%s is a directory",
  2500.                             expanded);
  2501.                         status_update(1);
  2502.                         load_depth--;
  2503. #ifdef ZCAT
  2504.                         new_free(&expand_z);
  2505. #endif /* ZCAT */
  2506.                         new_free(&expanded);
  2507.                         free_big_buffer(buffer);
  2508.                         return;
  2509.                     }
  2510.                     if (stat_buf.st_mode & 0111)
  2511.                     {
  2512.                         say("%s is executable and may \
  2513. not be loaded", expanded);
  2514.                         status_update(1);
  2515.                         load_depth--;
  2516. #ifdef ZCAT
  2517.                         new_free(&expand_z);
  2518. #endif /* ZCAT */
  2519.                         new_free(&expanded);
  2520.                         free_big_buffer(buffer);
  2521.                         return;
  2522.                     }
  2523.                 }
  2524.             if (command && *command == 'W')
  2525.             {
  2526.                 say("%s", expanded);
  2527.                 status_update(1);
  2528.                 load_depth--;
  2529.                 new_free(&expanded);
  2530.                 free_big_buffer(buffer);
  2531.                 return;
  2532.             }
  2533. #ifdef ZCAT
  2534.             /* Open if uncompressed, zcat if compressed */
  2535.             temp = &(expanded[strlen(expanded) - sizeof(ZSUFFIX)]);
  2536.             if (!strcmp(temp, ZSUFFIX))
  2537.                 fp = zcat(expanded);
  2538.             else
  2539.                 fp = fopen(expanded, "r");
  2540.             if (fp != NULL)
  2541. #else
  2542.                 if (fp = fopen(expanded, "r"))
  2543. #endif /*ZCAT*/
  2544.                 {
  2545.                     display = window_display;
  2546.                     window_display = 0;
  2547.                     current_row = NULL;
  2548.                     if (!flag)
  2549.                         args = NULL;
  2550.                     for (;;)
  2551.                     {
  2552.                         if (fgets(buffer, BIG_BUFFER_SIZE / 2, fp))
  2553.     {
  2554.         int    len;
  2555.         char    *ptr;
  2556.  
  2557.         for (start = buffer; isspace(*start); start++)
  2558.             ;
  2559.         if (!*start || *start == '#')
  2560.             continue;
  2561.  
  2562.         len = strlen(start);
  2563.     /*
  2564.      * this line from stargazer to allow \'s in scripts for continued
  2565.      * lines <spz@specklec.mpifr-bonn.mpg.de>
  2566.      */
  2567.         while (start[len-1] == '\n' && start[len-2] == '\\' &&
  2568.             len < BIG_BUFFER_SIZE / 2 && fgets(&(start[len-2]),
  2569.             BIG_BUFFER_SIZE / 2 - len, fp))
  2570.             len = strlen(start);
  2571.  
  2572.         if (start[len - 1] == '\n')
  2573.             start[--len] = '\0';
  2574.  
  2575.         while (start && *start)
  2576.         {
  2577.             char    *optr = start;
  2578.             while ((ptr = sindex(optr, "{};")) &&
  2579.                     ptr != optr &&
  2580.                     ptr[-1] == '\\')
  2581.                 optr = ptr+1;
  2582.  
  2583.             if (no_semicolon)
  2584.                 no_semicolon = 0;
  2585.             else if ((!ptr || ptr != start) && current_row)
  2586.             {
  2587.                 if (!paste_level)
  2588.                 {
  2589.                     parse_line(NULL, current_row,
  2590.                         args, 0, 0);
  2591.                     new_free(¤t_row);
  2592.                 }
  2593.                 else
  2594.                     malloc_strcat(¤t_row, ";");
  2595.             }
  2596.  
  2597.             if (ptr)
  2598.             {
  2599.                 char    c = *ptr;
  2600.  
  2601.                 *ptr = '\0';
  2602.                 malloc_strcat(¤t_row, start);
  2603.                 *ptr = c;
  2604.  
  2605.                 switch (c)
  2606.                 {
  2607.                 case '{' :
  2608.                     paste_level++;
  2609.                     if (ptr == start)
  2610.                         malloc_strcat(¤t_row, " {");
  2611.                     else
  2612.                         malloc_strcat(¤t_row, "{");
  2613.                     no_semicolon = 1;
  2614.                     break;
  2615.  
  2616.                 case '}' :
  2617.                     if (!paste_level)
  2618.                         yell("Unexpected }");
  2619.                     else
  2620.                     {
  2621.                         --paste_level;
  2622.                         malloc_strcat(¤t_row, "}");
  2623.                         no_semicolon = ptr[1] ? 1 : 0;
  2624.                     }
  2625.                     break;
  2626.  
  2627.                 case ';' :
  2628.                     malloc_strcat(¤t_row, ";");
  2629.                     no_semicolon = 1;
  2630.                     break;
  2631.                 }
  2632.  
  2633.                 start = ptr+1;
  2634.             }
  2635.             else
  2636.             {
  2637.                 malloc_strcat(¤t_row, start);
  2638.                 start = NULL;
  2639.             }
  2640.         }
  2641.     }
  2642.                         else
  2643.                             break;
  2644.                     }
  2645.                     if (current_row)
  2646.                     {
  2647.                         if (paste_level)
  2648.                             yell("Unexpected EOF");
  2649.                         else
  2650.                             parse_line(NULL,
  2651.                                 current_row, 
  2652.                                 args, 0, 0);
  2653.                         new_free(¤t_row);
  2654.                     }
  2655.                     window_display = display;
  2656.                     fclose(fp);
  2657.                 }
  2658.                 else
  2659.                     say("Couldn't open %s: %s", expanded,
  2660.                         strerror(errno));
  2661.             new_free(&expanded);
  2662.         }
  2663.         else
  2664.             say("Unknown user");
  2665.     }
  2666.     else
  2667.         say("No filename specified");
  2668.     status_update(1);
  2669.     load_depth--;
  2670.     free_big_buffer(buffer);
  2671. }
  2672.  
  2673. /*
  2674.  * get_history: gets the next history entry, either the PREV entry or the
  2675.  * NEXT entry, and sets it to the current input string 
  2676.  */
  2677. void    
  2678. get_history(which)
  2679.     int    which;
  2680. {
  2681.     char    *ptr;
  2682.  
  2683.     if ((ptr = get_from_history(which)) != NULL)
  2684.     {
  2685.         set_input(ptr);
  2686.         update_input(UPDATE_ALL);
  2687.     }
  2688. }
  2689.  
  2690. /* BIND function: */
  2691. void
  2692. forward_character()
  2693. {
  2694.     input_move_cursor(RIGHT);
  2695. }
  2696.  
  2697. void
  2698. backward_character()
  2699. {
  2700.     input_move_cursor(LEFT);
  2701. }
  2702.  
  2703. void
  2704. backward_history()
  2705. {
  2706.     get_history(PREV);
  2707. }
  2708.  
  2709. void
  2710. forward_history()
  2711. {
  2712.     get_history(NEXT);
  2713. }
  2714.  
  2715. void
  2716. toggle_insert_mode()
  2717. {
  2718.     set_var_value(INSERT_MODE_VAR, "TOGGLE");
  2719. }
  2720.  
  2721. /*ARGSUSED*/
  2722. void
  2723. send_line(key, ptr)
  2724.     char    *key;
  2725.     void    (*ptr)();
  2726. {
  2727.     int    server;
  2728.     WaitPrompt    *OldPrompt;
  2729.  
  2730.     server = from_server;
  2731.     from_server = get_window_server(0);
  2732.     reset_hold((Window *) 0);
  2733.     hold_mode((Window *) 0, OFF, 1);
  2734.     if (current_screen->promptlist && current_screen->promptlist->type == WAIT_PROMPT_LINE)
  2735.     {
  2736.         OldPrompt = current_screen->promptlist;
  2737.         (*OldPrompt->func)(OldPrompt->data, get_input());
  2738.         set_input(empty_string);
  2739.         current_screen->promptlist = OldPrompt->next;
  2740.         new_free(&OldPrompt->data);
  2741.         new_free(&OldPrompt->prompt);
  2742.         new_free(&OldPrompt);
  2743.         change_input_prompt(-1);
  2744.     }
  2745.     else
  2746.     {
  2747.         char    *line,
  2748.             *tmp = NULL;
  2749.  
  2750.         line = get_input();
  2751.         malloc_strcpy(&tmp, line);
  2752.  
  2753.         if (do_hook(INPUT_LIST, "%s", tmp))
  2754.         {
  2755.             if (get_int_var(INPUT_ALIASES_VAR))
  2756.                 parse_line(NULL, tmp, empty_string,
  2757.                     1, 0);
  2758.             else
  2759.                 parse_line(NULL, tmp, NULL,
  2760.                     1, 0);
  2761.         }
  2762.         update_input(UPDATE_ALL);
  2763.         new_free(&tmp);
  2764.     }
  2765.     from_server = server;
  2766. }
  2767.  
  2768. /* The SENDLINE command.. */
  2769. static    void
  2770. sendlinecmd(command, args)
  2771.     char    *command,
  2772.         *args;
  2773. {
  2774.     int    server;
  2775.     int    display;
  2776.  
  2777.     server = from_server;
  2778.     display = window_display;
  2779.     window_display = 1;
  2780.     if (get_int_var(INPUT_ALIASES_VAR))
  2781.         parse_line(NULL, args, empty_string, 1, 0);
  2782.     else
  2783.         parse_line(NULL, args, NULL, 1, 0);
  2784.     update_input(UPDATE_ALL);
  2785.     window_display = display;
  2786.     from_server = server;
  2787. }
  2788.  
  2789. /*ARGSUSED*/
  2790. void
  2791. meta4_char(key, ptr)
  2792.     char    *key;
  2793.     void    (*ptr)();
  2794. {
  2795.     current_screen->meta4_hit = 1 - current_screen->meta4_hit;
  2796. }
  2797.  
  2798. /*ARGSUSED*/
  2799. void
  2800. meta3_char(key, ptr)
  2801.     char    *key;
  2802.     void    (*ptr)();
  2803. {
  2804.     current_screen->meta3_hit = 1;
  2805. }
  2806.  
  2807. /*ARGSUSED*/
  2808. void
  2809. meta2_char(key, ptr)
  2810.     char    *key;
  2811.     void    (*ptr)();
  2812. {
  2813.     current_screen->meta2_hit = 1;
  2814. }
  2815.  
  2816. /*ARGSUSED*/
  2817. void
  2818. meta1_char(key, ptr)
  2819.     char    *key;
  2820.     void    (*ptr)();
  2821. {
  2822.     current_screen->meta1_hit = 1;
  2823. }
  2824.  
  2825. void
  2826. quote_char(c)
  2827.     char    c;
  2828. {
  2829.     current_screen->quote_hit = 1;
  2830. }
  2831.  
  2832. /* type_text: the BIND function TYPE_TEXT */
  2833. /*ARGSUSED*/
  2834. void
  2835. type_text(c, str)
  2836.     char    c,
  2837.         *str;
  2838. {
  2839.     for (; *str; str++)
  2840.         input_add_character(*str);
  2841. }
  2842.  
  2843. /*
  2844.  * clear_screen: the CLEAR_SCREEN function for BIND.  Clears the screen and
  2845.  * starts it if it is held 
  2846.  */
  2847. /*ARGSUSED*/
  2848. void
  2849. clear_screen(c, str)
  2850.     char    c,
  2851.         *str;
  2852. {
  2853.     hold_mode((Window *) 0, OFF, 1);
  2854.     clear(NULL, empty_string);
  2855. }
  2856.  
  2857. /* parse_text: the bindable function that executes its string */
  2858. void
  2859. parse_text(c, str)
  2860.     char    c,
  2861.         *str;
  2862. {
  2863.     parse_line(NULL, str, empty_string, 0, 0);
  2864. }
  2865.  
  2866. /*
  2867.  * edit_char: handles each character for an input stream.  Not too difficult
  2868.  * to work out.
  2869.  */
  2870. void
  2871. edit_char(key)
  2872.     u_char    key;
  2873. {
  2874.     void    (*func) ();
  2875.     char    *ptr;
  2876.     u_char    extended_key;
  2877.     WaitPrompt *oldprompt;
  2878.  
  2879.     if (current_screen->promptlist &&
  2880.             current_screen->promptlist->type == WAIT_PROMPT_KEY)
  2881.     {
  2882.         oldprompt = current_screen->promptlist;
  2883.         (*oldprompt->func)(oldprompt->data, &key);
  2884.         set_input(empty_string);
  2885.         current_screen->promptlist = oldprompt->next;
  2886.         new_free(&oldprompt->data);
  2887.         new_free(&oldprompt->prompt);
  2888.         new_free(&oldprompt);
  2889.         change_input_prompt(-1);
  2890.         return;
  2891.     }
  2892.     if (!get_int_var(EIGHT_BIT_CHARACTERS_VAR))
  2893.         key &= 0x7f;            /* mask out non-ascii crap */
  2894.  
  2895.     if (translation)
  2896.         extended_key = transFromClient[key];
  2897.     else
  2898.         extended_key = key;
  2899.  
  2900.     if (current_screen->meta1_hit)
  2901.     {
  2902.         func = key_names[meta1_keys[key].index].func;
  2903.         ptr = meta1_keys[key].stuff;
  2904.         current_screen->meta1_hit = 0;
  2905.     }
  2906.     else if (current_screen->meta2_hit)
  2907.     {
  2908.         func = key_names[meta2_keys[key].index].func;
  2909.         ptr = meta2_keys[key].stuff;
  2910.         current_screen->meta2_hit = 0;
  2911.     }
  2912.     else if (current_screen->meta3_hit)
  2913.     {
  2914.         func = key_names[meta3_keys[key].index].func;
  2915.         ptr = meta3_keys[key].stuff;
  2916.         current_screen->meta3_hit = 0;
  2917.     }
  2918.     else if (current_screen->meta4_hit)
  2919.     {
  2920.         func = key_names[meta4_keys[key].index].func;
  2921.         ptr = meta4_keys[key].stuff;
  2922.     }
  2923.     else
  2924.     {
  2925.         func = key_names[keys[key].index].func;
  2926.         ptr = keys[key].stuff;
  2927.     }
  2928.     if (!current_screen->meta1_hit && !current_screen->meta2_hit &&
  2929.             !current_screen->meta3_hit)
  2930.     {
  2931.         if (current_screen->inside_menu == 1)
  2932.             menu_key(key);
  2933.         else if (current_screen->digraph_hit)
  2934.         {
  2935.             if (extended_key == 0x08 || extended_key == 0x7f)
  2936.                 current_screen->digraph_hit = 0;
  2937.             else if (current_screen->digraph_hit == 1)
  2938.             {
  2939.                 current_screen->digraph_first = extended_key;
  2940.                 current_screen->digraph_hit = 2;
  2941.             }
  2942.             else if (current_screen->digraph_hit == 2)
  2943.             {
  2944.                 if ((extended_key =
  2945.                     get_digraph(extended_key)) != '\0')
  2946.                     input_add_character(extended_key);
  2947.                 else
  2948.                     term_beep();
  2949.             }
  2950.         }
  2951.         else if (current_screen->quote_hit)
  2952.         {
  2953.             current_screen->quote_hit = 0;
  2954.             input_add_character(extended_key);
  2955.         }
  2956.         else if (func)
  2957.             func(extended_key, ptr ? ptr : empty_string);
  2958.     }
  2959.     else
  2960.         term_beep();
  2961. }
  2962.  
  2963. /*ARGSUSED*/
  2964. static    void
  2965. cd(command, args)
  2966.     char    *command,
  2967.         *args;
  2968. {
  2969.     char    *arg,
  2970.         *expand;
  2971.  
  2972. #ifdef DAEMON_UID
  2973.     if (getuid() == DAEMON_UID)
  2974.     {
  2975.         say("You are not permitted to use this command");
  2976.         return;
  2977.     }
  2978. #endif /* DAEMON_UID */
  2979.     if ((arg = next_arg(args, &args)) != NULL)
  2980.     {
  2981.         if ((expand = expand_twiddle(arg)) != NULL)
  2982.         {
  2983.             if (chdir(expand))
  2984.                 say("CD: %s", strerror(errno));
  2985.             new_free(&expand);
  2986.         }
  2987.         else
  2988.             say("CD: No such user");
  2989.     }
  2990.     getcwd(buffer, BIG_BUFFER_SIZE+1);
  2991.     /* is this more portable? *shrug*. i chose BIG_BUFFER_SIZE+1 
  2992.        because it's more readable -cgw- */
  2993.     /* getcwd((char *)buffer, sizeof((char *)buffer)); */
  2994.     say("Current directory: %s", buffer);
  2995. }
  2996.  
  2997. static    void
  2998. send_action(target, text)
  2999.     char    *target, *text;
  3000. {
  3001.     send_ctcp(ctcp_type[CTCP_PRIVMSG], target, "ACTION", "%s", text);
  3002. }
  3003.  
  3004. #if LYNX_STUFF
  3005. static    char    *
  3006. prepare_action(string)
  3007.     char    *string;
  3008. {
  3009.     short    last;
  3010.     char    *message;
  3011.  
  3012.     last = strlen(string) - 1;
  3013.     while(string[last] == ' ')
  3014.         if (--last < 0) return NULL;
  3015.  
  3016.     if ((string[last] > 'a' && string[last] < 'z') ||
  3017.             (string[last] > 'A' && string[last] < 'Z'))
  3018.     {
  3019.         message = new_malloc(last + 2);
  3020.         strmcpy (message, string, last+1);
  3021.         message[last + 1] = '.';
  3022.         message[last + 2] = '\0';
  3023.         return message;
  3024.     }
  3025.     else
  3026.         return NULL;
  3027. }
  3028. #endif
  3029.  
  3030. static    void
  3031. describe(command, args)
  3032.     char    *command,
  3033.         *args;
  3034. {
  3035.     char    *target;
  3036.  
  3037.     target = next_arg(args, &args);
  3038.     if (target && args && *args)
  3039.     {
  3040.         int    old;
  3041.         int    from_level;
  3042. #if LYNX_STUFF
  3043.         char    *result;
  3044. #endif
  3045.         char    *message;
  3046.  
  3047. #if LYNX_STUFF
  3048.         if (result = prepare_action(args))
  3049.             message = result;
  3050.         else
  3051. #endif
  3052.             message = args;
  3053.         send_action(target, message);
  3054.  
  3055.         old = set_lastlog_msg_level(LOG_ACTION);
  3056.         from_level = message_from_level(LOG_ACTION);
  3057.         if (do_hook(SEND_ACTION_LIST, "%s %s", target, message))
  3058.             put_it("* -> %s: %s %s", target,
  3059.                 get_server_nickname(from_server), message);
  3060.         set_lastlog_msg_level(old);
  3061.         message_from_level(from_level);
  3062.  
  3063. #if LYNX_STUFF
  3064.         if (result)
  3065.             new_free(&result);
  3066. #endif
  3067.     }
  3068.     else
  3069.         say("Usage: /DESCRIBE <target> <action description>");
  3070. }
  3071.  
  3072. /*
  3073.  * New 'me' command - now automatically appends period.
  3074.  * Necessary for new 'action' script.   -lynx'92
  3075.  * Hardly, removed this as it was generally considered offensive
  3076.  */
  3077. static    void
  3078. me(command, args)
  3079.     char    *command,
  3080.         *args;
  3081. {
  3082.     if (args && *args)
  3083.     {
  3084.         char    *target;
  3085.  
  3086.         if ((target = get_target_by_refnum(0)) != NULL)
  3087.         {
  3088.             int    old;
  3089.             int    from_level;
  3090. #if LYNX_STUFF
  3091.             char    *result;
  3092. #endif
  3093.             char    *message;
  3094.  
  3095.             if (*target == '=' || !strncmp(target,
  3096.                     get_string_var(CMDCHARS_VAR), 1))
  3097.                 if (!(target = get_channel_by_refnum(0)))
  3098.                 {
  3099.                     say("No target, neither channel nor \
  3100. query");
  3101.                     return;
  3102.                 }
  3103. #if LYNX_STUFF
  3104.             if (result = prepare_action(args))
  3105.                 message = result;
  3106.             else
  3107. #endif
  3108.                 message = args;
  3109.             send_action(target, message);
  3110.  
  3111.             old = set_lastlog_msg_level(LOG_ACTION);
  3112.             message_from(target, LOG_ACTION);
  3113.             if (do_hook(SEND_ACTION_LIST, "%s %s", target, message))
  3114.                 put_it("* %s %s",
  3115.                     get_server_nickname(from_server), message);
  3116.             set_lastlog_msg_level(old);
  3117.  
  3118. #if LYNX_STUFF
  3119.             if (result)
  3120.                 new_free(&result);
  3121. #endif
  3122.         }
  3123.         else
  3124.             say("No target, neither channel nor query");
  3125.     }
  3126.     else
  3127.         say("Usage: /ME <action description>");
  3128. }
  3129.  
  3130. static    void
  3131. mload(command, args)
  3132.     char    *command,
  3133.         *args;
  3134. {
  3135.     char    *file;
  3136.  
  3137.     while ((file = next_arg(args, &args)) != NULL)
  3138.         load_menu(file);
  3139. }
  3140.  
  3141. static    void
  3142. mlist(command, args)
  3143.     char    *command,
  3144.         *args;
  3145. {
  3146.     char    *menu;
  3147.  
  3148.     while ((menu = new_next_arg(args, &args)) != NULL)
  3149.         (void) ShowMenu(menu, 0);
  3150. }
  3151.  
  3152. static    void
  3153. evalcmd(command, args, subargs)
  3154.     char    *command,
  3155.         *args,
  3156.         *subargs;
  3157. {
  3158.     parse_line(NULL, args, subargs ? subargs : empty_string, 0, 0);
  3159. }
  3160.  
  3161. /*
  3162.  * ExecuteTimers:  checks to see if any currently pending timers have
  3163.  * gone off, and if so, execute them, delete them, etc, setting the
  3164.  * current_exec_timer, so that we can't remove the timer while its
  3165.  * still executing.
  3166.  */
  3167. extern    void
  3168. ExecuteTimers()
  3169. {
  3170.     time_t    current;
  3171.     TimerList *next;
  3172.     int    old_in_on_who;
  3173.  
  3174.     time(¤t);
  3175.     while (PendingTimers && PendingTimers->time <= current)
  3176.     {
  3177.         old_in_on_who = in_on_who;
  3178.         in_on_who = PendingTimers->in_on_who;
  3179.         current_exec_timer = PendingTimers->ref;
  3180.         parse_command(PendingTimers->command, 0, empty_string);
  3181.         current_exec_timer = -1;
  3182.         new_free(&PendingTimers->command);
  3183.         next = PendingTimers->next;
  3184.         new_free(&PendingTimers);
  3185.         PendingTimers = next;
  3186.         in_on_who = old_in_on_who;
  3187.     }
  3188. }
  3189.  
  3190. /*
  3191.  * timercmd: the bit that handles the TIMER command.  If there are no
  3192.  * arguements, then just list the currently pending timers, if we are
  3193.  * give a -DELETE flag, attempt to delete the timer from the list.  Else
  3194.  * consider it to be a timer to add, and add it.
  3195.  */
  3196. static    void
  3197. timercmd(command, args)
  3198.     char    *command;
  3199.     char    *args;
  3200. {
  3201.     char    *waittime,
  3202.         *flag;
  3203.     time_t    current;
  3204.     TimerList    **slot,
  3205.             *ntimer;
  3206.     int    want = -1,
  3207.         refnum;
  3208.  
  3209.     if (*args == '-')
  3210.     {
  3211.         int    len;
  3212.  
  3213.         flag = next_arg(args, &args);
  3214.         len = strlen(flag);
  3215.  
  3216.         /* first check for the -DELETE flag */
  3217.  
  3218.         if (!my_strnicmp(flag, "-DELETE", len))
  3219.         {
  3220.             char    *ptr;
  3221.             int    ref;
  3222.             TimerList    *tmp,
  3223.                     *prev;
  3224.  
  3225.             if (current_exec_timer != -1)
  3226.             {
  3227.                 say("You may not remove a TIMER from itself");
  3228.                 return;
  3229.             }
  3230.             if (!(ptr = next_arg(args, &args)))
  3231.             {
  3232.                 say("%s: Need a timer reference number for -DELETE", command);
  3233.                 return;
  3234.             }
  3235.             ref = atoi(ptr);
  3236.             for (prev = tmp = PendingTimers; tmp; prev = tmp,
  3237.                     tmp = tmp->next)
  3238.             {
  3239.                 if (tmp->ref == ref)
  3240.                 {
  3241.                     if (tmp == prev)
  3242.                         PendingTimers =
  3243.                             PendingTimers->next;
  3244.                     else
  3245.                         prev->next = tmp->next;
  3246.                     new_free(&tmp->command);
  3247.                     new_free(&tmp);
  3248.                     return;
  3249.                 }
  3250.             }
  3251.             say("%s: Can't delete %d, no such refnum",
  3252.                 command, ref);
  3253.             return;
  3254.         }
  3255.         else if (!my_strnicmp(flag, "-REFNUM", len))
  3256.         {
  3257.             char    *ptr;
  3258.  
  3259.             ptr = next_arg(args, &args);
  3260.             want = atoi(ptr);
  3261.             if (want < 0)
  3262.             {
  3263.                 say("%s: Illegal refnum %d", command, want);
  3264.                 return;
  3265.             }
  3266.         }
  3267.         else
  3268.         {
  3269.             say("%s: %s no such flag", command, flag);
  3270.             return;
  3271.         }
  3272.     }
  3273.  
  3274.     /* else check to see if we have no args -> list */
  3275.  
  3276.     if (!(waittime = next_arg(args, &args)))
  3277.     {
  3278.         show_timer(command);
  3279.         return;
  3280.     }
  3281.  
  3282.     /* must be something to add */
  3283.  
  3284.     if ((refnum = create_timer_ref(want)) == -1)
  3285.     {
  3286.         say("%s: Refnum %d already exists", command, want);
  3287.         return;
  3288.     }
  3289.     time(¤t);
  3290.     ntimer = (TimerList *) new_malloc(sizeof(TimerList));
  3291.     ntimer->in_on_who = in_on_who;
  3292.     ntimer->time = current + atol(waittime);
  3293.     ntimer->ref = refnum;
  3294.     ntimer->command = NULL;
  3295.     malloc_strcpy(&ntimer->command, args);
  3296.  
  3297.     /* we've created it, now put it in order */
  3298.  
  3299.     for (slot = &PendingTimers; *slot; slot = &(*slot)->next)
  3300.     {
  3301.         if ((*slot)->time > ntimer->time)
  3302.             break;
  3303.     }
  3304.     ntimer->next = *slot;
  3305.     *slot = ntimer;
  3306. }
  3307.  
  3308. /*
  3309.  * show_timer:  Display a list of all the TIMER commands that are
  3310.  * pending to be executed.
  3311.  */
  3312. static    void
  3313. show_timer(command)
  3314.     char    *command;
  3315. {
  3316.     TimerList    *tmp;
  3317.     time_t    current,
  3318.         time_left;
  3319.  
  3320.     if (!PendingTimers)
  3321.     {
  3322.         say("%s: No commands pending to be executed", command);
  3323.         return;
  3324.     }
  3325.  
  3326.     time(¤t);
  3327.     say("Timer Seconds   Command");
  3328.     for (tmp = PendingTimers; tmp; tmp = tmp->next)
  3329.     {
  3330.         time_left = tmp->time - current;
  3331.         if (time_left < 0)
  3332.             time_left = 0;
  3333.         say("%-5d %-10d %s", tmp->ref, time_left, tmp->command);
  3334.     }
  3335. }
  3336.  
  3337. /*
  3338.  * create_timer_ref:  returns the lowest unused reference number for
  3339.  * a timer
  3340.  */
  3341. static    int
  3342. create_timer_ref(want)
  3343.     int    want;
  3344. {
  3345.     TimerList    *tmp;
  3346.     int    ref = 0;
  3347.     int    done = 0;
  3348.  
  3349.     if (want == -1)
  3350.         while (!done)
  3351.         {
  3352.             done = 1;
  3353.             for (tmp = PendingTimers; tmp; tmp = tmp->next)
  3354.                 if (ref == tmp->ref)
  3355.                 {
  3356.                     ref++;
  3357.                     done = 0;
  3358.                     break;
  3359.                 }
  3360.         }
  3361.     else
  3362.     {
  3363.         ref = want;
  3364.         for (tmp = PendingTimers; tmp; tmp = tmp->next)
  3365.             if (ref == tmp->ref)
  3366.             {
  3367.                 ref = -1;
  3368.                 break;
  3369.             }
  3370.     }
  3371.  
  3372.     return (ref);
  3373. }
  3374.  
  3375. /*
  3376.  * inputcmd:  the INPUT command.   Takes a couple of arguements...
  3377.  * the first surrounded in double quotes, and the rest makes up
  3378.  * a normal ircII command.  The command is evalutated, with $*
  3379.  * being the line that you input.  Used add_wait_prompt() to prompt
  3380.  * the user...  -phone, jan 1993.
  3381.  */
  3382.  
  3383. static    void
  3384. inputcmd(command, args)
  3385.     char    *command,
  3386.         *args;
  3387. {
  3388.     char    *prompt;
  3389.  
  3390.     if (!args || !*args)
  3391.         return;
  3392.     
  3393.     if (*args++ != '"')
  3394.     {
  3395.         say("Need \" to begin prompt for INPUT");
  3396.         return;
  3397.     }
  3398.  
  3399.     prompt = args;
  3400.     if ((args = index(prompt, '"')) != NULL)
  3401.         *args++ = '\0';
  3402.     else
  3403.     {
  3404.         say("Missing \" in INPUT");
  3405.         return;
  3406.     }
  3407.  
  3408.     for (; *args == ' '; args++)
  3409.         ;
  3410.  
  3411.     add_wait_prompt(prompt, eval_inputlist, args, WAIT_PROMPT_LINE);
  3412. }
  3413.  
  3414. /*
  3415.  * eval_inputlist:  Cute little wrapper that calls parse_line() when we
  3416.  * get an input prompt ..
  3417.  */
  3418.  
  3419. void
  3420. eval_inputlist(args, line)
  3421.     char    *args,
  3422.         *line;
  3423. {
  3424.     parse_line(NULL, args, line ? line : empty_string, 0, 0);
  3425. }
  3426.  
  3427. /* pingcmd: ctcp ping, duh - phone, jan 1993. */
  3428. static    void
  3429. pingcmd(command, args)
  3430.     char    *command,
  3431.         *args;
  3432. {
  3433.     sprintf(buffer, "%s PING %ld", args, time(NULL));
  3434.     ctcp(command, buffer);
  3435. }
  3436.  
  3437. static    void
  3438. xtypecmd(command, args)
  3439.     char    *command,
  3440.         *args;
  3441. {
  3442.     char    *arg;
  3443.     int    len;
  3444.  
  3445.     if (*args == '-')
  3446.     {
  3447.         args++;
  3448.         if ((arg = next_arg(args, &args)) != NULL)
  3449.         {
  3450.             len = strlen(arg);
  3451.             if (!my_strnicmp(arg, "LITERAL", len))
  3452.             {
  3453.                 for (; *args; args++)
  3454.                     input_add_character(*args);
  3455.             }
  3456.             else if (!my_strnicmp(arg, "REPLACE", len))
  3457.             {
  3458.                 set_input(args);
  3459.             }
  3460.             else
  3461.                 say ("Unknown flag -%s to XTYPE", arg);
  3462.             return;
  3463.         }
  3464.         input_add_character('-');
  3465.     }
  3466.     else
  3467.         type(command, args);
  3468.     return;
  3469. }
  3470.  
  3471. static    void
  3472. beepcmd(command, args)
  3473.     char    *command,
  3474.         *args;
  3475. {
  3476.     term_beep();
  3477. }
  3478.